Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "excimp8.hxx"
21 :
22 : #include <boost/bind.hpp>
23 :
24 : #include <scitems.hxx>
25 : #include <comphelper/processfactory.hxx>
26 : #include <comphelper/mediadescriptor.hxx>
27 : #include <unotools/fltrcfg.hxx>
28 :
29 : #include <vcl/wmf.hxx>
30 :
31 : #include <editeng/eeitem.hxx>
32 :
33 : #include <sfx2/docfile.hxx>
34 : #include <sfx2/objsh.hxx>
35 : #include <sfx2/request.hxx>
36 : #include <sfx2/app.hxx>
37 : #include <sfx2/docinf.hxx>
38 : #include <sfx2/frame.hxx>
39 :
40 : #include <editeng/brushitem.hxx>
41 : #include <editeng/editdata.hxx>
42 : #include <editeng/editeng.hxx>
43 : #include <editeng/editobj.hxx>
44 : #include <editeng/editstat.hxx>
45 : #include <editeng/colritem.hxx>
46 : #include <editeng/udlnitem.hxx>
47 : #include <editeng/wghtitem.hxx>
48 : #include <editeng/postitem.hxx>
49 : #include <editeng/crossedoutitem.hxx>
50 : #include <editeng/flditem.hxx>
51 : #include <svx/xflclit.hxx>
52 :
53 : #include <vcl/graph.hxx>
54 : #include <vcl/bmpacc.hxx>
55 : #include <sot/exchange.hxx>
56 :
57 : #include <svl/stritem.hxx>
58 :
59 : #include <tools/string.hxx>
60 : #include <rtl/math.hxx>
61 : #include <unotools/localedatawrapper.hxx>
62 : #include <unotools/charclass.hxx>
63 : #include <drwlayer.hxx>
64 :
65 : #include <boost/scoped_array.hpp>
66 :
67 : #include "formulacell.hxx"
68 : #include "document.hxx"
69 : #include "patattr.hxx"
70 : #include "docpool.hxx"
71 : #include "attrib.hxx"
72 : #include "conditio.hxx"
73 : #include "dbdata.hxx"
74 : #include "globalnames.hxx"
75 : #include "editutil.hxx"
76 : #include "markdata.hxx"
77 : #include "rangenam.hxx"
78 : #include "docoptio.hxx"
79 : #include "globstr.hrc"
80 : #include "fprogressbar.hxx"
81 : #include "xltracer.hxx"
82 : #include "xihelper.hxx"
83 : #include "xipage.hxx"
84 : #include "xicontent.hxx"
85 : #include "xilink.hxx"
86 : #include "xiescher.hxx"
87 : #include "xipivot.hxx"
88 :
89 : #include "excform.hxx"
90 : #include "scextopt.hxx"
91 : #include "stlpool.hxx"
92 : #include "stlsheet.hxx"
93 : #include "detfunc.hxx"
94 : #include "macromgr.hxx"
95 : #include "queryentry.hxx"
96 :
97 : #include <com/sun/star/document/XDocumentProperties.hpp>
98 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
99 : #include <com/sun/star/script/ModuleInfo.hpp>
100 : #include <com/sun/star/container/XIndexContainer.hpp>
101 : #include <cppuhelper/component_context.hxx>
102 : #include "xltoolbar.hxx"
103 : #include <oox/ole/vbaproject.hxx>
104 : #include <oox/ole/olestorage.hxx>
105 : #include <unotools/streamwrap.hxx>
106 :
107 : using namespace com::sun::star;
108 : using namespace ::comphelper;
109 :
110 : //OleNameOverrideContainer
111 :
112 : typedef ::cppu::WeakImplHelper1< container::XNameContainer > OleNameOverrideContainer_BASE;
113 :
114 81 : class OleNameOverrideContainer : public OleNameOverrideContainer_BASE
115 : {
116 : private:
117 : typedef boost::unordered_map< OUString, uno::Reference< container::XIndexContainer >, OUStringHash,
118 : ::std::equal_to< OUString > > NamedIndexToOleName;
119 : NamedIndexToOleName IdToOleNameHash;
120 : ::osl::Mutex m_aMutex;
121 : public:
122 : // XElementAccess
123 0 : virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException) { return container::XIndexContainer::static_type(0); }
124 0 : virtual ::sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException)
125 : {
126 0 : ::osl::MutexGuard aGuard( m_aMutex );
127 0 : return ( IdToOleNameHash.size() > 0 );
128 : }
129 : // XNameAcess
130 0 : virtual uno::Any SAL_CALL getByName( const OUString& aName ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
131 : {
132 0 : ::osl::MutexGuard aGuard( m_aMutex );
133 0 : if ( !hasByName(aName) )
134 0 : throw container::NoSuchElementException();
135 0 : return uno::makeAny( IdToOleNameHash[ aName ] );
136 : }
137 0 : virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) throw (uno::RuntimeException)
138 : {
139 0 : ::osl::MutexGuard aGuard( m_aMutex );
140 0 : uno::Sequence< OUString > aResult( IdToOleNameHash.size() );
141 0 : NamedIndexToOleName::iterator it = IdToOleNameHash.begin();
142 0 : NamedIndexToOleName::iterator it_end = IdToOleNameHash.end();
143 0 : OUString* pName = aResult.getArray();
144 0 : for (; it != it_end; ++it, ++pName )
145 0 : *pName = it->first;
146 0 : return aResult;
147 : }
148 87 : virtual ::sal_Bool SAL_CALL hasByName( const OUString& aName ) throw (uno::RuntimeException)
149 : {
150 87 : ::osl::MutexGuard aGuard( m_aMutex );
151 87 : return ( IdToOleNameHash.find( aName ) != IdToOleNameHash.end() );
152 : }
153 :
154 : // XElementAccess
155 0 : virtual ::sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException)
156 : {
157 0 : ::osl::MutexGuard aGuard( m_aMutex );
158 0 : return IdToOleNameHash.size();
159 : }
160 : // XNameContainer
161 0 : virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::ElementExistException, lang::WrappedTargetException, uno::RuntimeException)
162 : {
163 0 : ::osl::MutexGuard aGuard( m_aMutex );
164 0 : if ( hasByName( aName ) )
165 0 : throw container::ElementExistException();
166 0 : uno::Reference< container::XIndexContainer > xElement;
167 0 : if ( ! ( aElement >>= xElement ) )
168 0 : throw lang::IllegalArgumentException();
169 0 : IdToOleNameHash[ aName ] = xElement;
170 0 : }
171 0 : virtual void SAL_CALL removeByName( const OUString& aName ) throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
172 : {
173 0 : ::osl::MutexGuard aGuard( m_aMutex );
174 0 : if ( !hasByName( aName ) )
175 0 : throw container::NoSuchElementException();
176 0 : IdToOleNameHash.erase( IdToOleNameHash.find( aName ) );
177 0 : }
178 0 : virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
179 : {
180 0 : ::osl::MutexGuard aGuard( m_aMutex );
181 0 : if ( !hasByName( aName ) )
182 0 : throw container::NoSuchElementException();
183 0 : uno::Reference< container::XIndexContainer > xElement;
184 0 : if ( ! ( aElement >>= xElement ) )
185 0 : throw lang::IllegalArgumentException();
186 0 : IdToOleNameHash[ aName ] = xElement;
187 0 : }
188 : };
189 :
190 46 : ImportExcel8::ImportExcel8( XclImpRootData& rImpData, SvStream& rStrm ) :
191 46 : ImportExcel( rImpData, rStrm )
192 : {
193 : // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
194 46 : delete pFormConv;
195 46 : pFormConv = pExcRoot->pFmlaConverter = new ExcelToSc8( GetRoot() );
196 46 : }
197 :
198 :
199 92 : ImportExcel8::~ImportExcel8()
200 : {
201 92 : }
202 :
203 :
204 138 : void ImportExcel8::Calccount( void )
205 : {
206 138 : ScDocOptions aOpt = pD->GetDocOptions();
207 138 : aOpt.SetIterCount( aIn.ReaduInt16() );
208 138 : pD->SetDocOptions( aOpt );
209 138 : }
210 :
211 :
212 43 : void ImportExcel8::Precision( void )
213 : {
214 43 : ScDocOptions aOpt = pD->GetDocOptions();
215 43 : aOpt.SetCalcAsShown( aIn.ReaduInt16() == 0 );
216 43 : pD->SetDocOptions( aOpt );
217 43 : }
218 :
219 :
220 154 : void ImportExcel8::Delta( void )
221 : {
222 154 : ScDocOptions aOpt = pD->GetDocOptions();
223 154 : aOpt.SetIterEps( aIn.ReadDouble() );
224 154 : pD->SetDocOptions( aOpt );
225 154 : }
226 :
227 :
228 154 : void ImportExcel8::Iteration( void )
229 : {
230 154 : ScDocOptions aOpt = pD->GetDocOptions();
231 154 : aOpt.SetIter( aIn.ReaduInt16() == 1 );
232 154 : pD->SetDocOptions( aOpt );
233 154 : }
234 :
235 :
236 157 : void ImportExcel8::Boundsheet( void )
237 : {
238 : sal_uInt8 nLen;
239 : sal_uInt16 nGrbit;
240 :
241 157 : aIn.DisableDecryption();
242 157 : maSheetOffsets.push_back( aIn.ReaduInt32() );
243 157 : aIn.EnableDecryption();
244 157 : aIn >> nGrbit >> nLen;
245 :
246 157 : OUString aName( aIn.ReadUniString( nLen ) );
247 157 : GetTabInfo().AppendXclTabName( aName, nBdshtTab );
248 :
249 157 : SCTAB nScTab = static_cast< SCTAB >( nBdshtTab );
250 157 : if( nScTab > 0 )
251 : {
252 : OSL_ENSURE( !pD->HasTable( nScTab ), "ImportExcel8::Boundsheet - sheet exists already" );
253 113 : pD->MakeTable( nScTab );
254 : }
255 :
256 157 : if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) )
257 9 : pD->SetVisible( nScTab, false );
258 :
259 157 : if( !pD->RenameTab( nScTab, aName ) )
260 : {
261 0 : pD->CreateValidTabName( aName );
262 0 : pD->RenameTab( nScTab, aName );
263 : }
264 :
265 157 : nBdshtTab++;
266 157 : }
267 :
268 :
269 0 : void ImportExcel8::Scenman( void )
270 : {
271 : sal_uInt16 nLastDispl;
272 :
273 0 : aIn.Ignore( 4 );
274 0 : aIn >> nLastDispl;
275 :
276 0 : maScenList.nLastScenario = nLastDispl;
277 0 : }
278 :
279 :
280 0 : void ImportExcel8::Scenario( void )
281 : {
282 0 : maScenList.aEntries.push_back( new ExcScenario( aIn, *pExcRoot ) );
283 0 : }
284 :
285 :
286 10614 : void ImportExcel8::Labelsst( void )
287 : {
288 10614 : XclAddress aXclPos;
289 : sal_uInt16 nXF;
290 : sal_uInt32 nSst;
291 :
292 10614 : aIn >> aXclPos >> nXF >> nSst;
293 :
294 10614 : ScAddress aScPos( ScAddress::UNINITIALIZED );
295 10614 : if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
296 : {
297 10614 : GetXFRangeBuffer().SetXF( aScPos, nXF );
298 10614 : const XclImpString* pXclStr = GetSst().GetString(nSst);
299 10614 : if (pXclStr)
300 10614 : XclImpStringHelper::SetToDocument(GetDoc(), aScPos, *this, *pXclStr, nXF);
301 : }
302 10614 : }
303 :
304 :
305 81 : void ImportExcel8::SheetProtection( void )
306 : {
307 81 : GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
308 81 : }
309 :
310 27 : void ImportExcel8::ReadBasic( void )
311 : {
312 27 : SfxObjectShell* pShell = GetDocShell();
313 27 : SotStorageRef xRootStrg = GetRootStorage();
314 27 : const SvtFilterOptions& rFilterOpt = SvtFilterOptions::Get();
315 27 : if( pShell && xRootStrg.Is() ) try
316 : {
317 : // #FIXME need to get rid of this, we can also do this from within oox
318 : // via the "ooo.vba.VBAGlobals" service
319 54 : if( ( rFilterOpt.IsLoadExcelBasicCode() ||
320 54 : rFilterOpt.IsLoadExcelBasicStorage() ) &&
321 27 : rFilterOpt.IsLoadExcelBasicExecutable() )
322 : {
323 : // see if we have the XCB stream
324 27 : SvStorageStreamRef xXCB = xRootStrg->OpenSotStream( String( RTL_CONSTASCII_USTRINGPARAM( "XCB" ) ), STREAM_STD_READ | STREAM_NOCREATE );
325 27 : if ( xXCB.Is()|| SVSTREAM_OK == xXCB->GetError() )
326 : {
327 27 : ScCTBWrapper wrapper;
328 27 : if ( wrapper.Read( *xXCB ) )
329 : {
330 : #if OSL_DEBUG_LEVEL > 1
331 : wrapper.Print( stderr );
332 : #endif
333 27 : wrapper.ImportCustomToolBar( *pShell );
334 27 : }
335 27 : }
336 : }
337 : try
338 : {
339 27 : uno::Reference< uno::XComponentContext > aCtx( ::comphelper::getProcessComponentContext() );
340 27 : SfxMedium& rMedium = GetMedium();
341 54 : uno::Reference< io::XInputStream > xIn = rMedium.GetInputStream();
342 54 : oox::ole::OleStorage root( aCtx, xIn, false );
343 54 : oox::StorageRef vbaStg = root.openSubStorage( "_VBA_PROJECT_CUR", false );
344 27 : if ( vbaStg.get() )
345 : {
346 27 : oox::ole::VbaProject aVbaPrj( aCtx, pShell->GetModel(), "Calc" );
347 : // collect names of embedded form controls, as specified in the VBA project
348 54 : uno::Reference< container::XNameContainer > xOleNameOverrideSink( new OleNameOverrideContainer );
349 27 : aVbaPrj.setOleOverridesSink( xOleNameOverrideSink );
350 27 : aVbaPrj.importVbaProject( *vbaStg );
351 54 : GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink );
352 27 : }
353 : }
354 0 : catch( uno::Exception& )
355 : {
356 : }
357 : }
358 0 : catch( uno::Exception& )
359 : {
360 27 : }
361 27 : }
362 :
363 :
364 156 : void ImportExcel8::EndSheet( void )
365 : {
366 156 : ImportExcel::EndSheet();
367 156 : GetCondFormatManager().Apply();
368 156 : GetValidationManager().Apply();
369 156 : }
370 :
371 :
372 46 : void ImportExcel8::PostDocLoad( void )
373 : {
374 : #ifndef DISABLE_SCRIPTING
375 : // reading basic has been delayed until sheet objects (codenames etc.) are read
376 46 : if( HasBasic() )
377 27 : ReadBasic();
378 : #endif
379 : // #i11776# filtered ranges before outlines and hidden rows
380 46 : if( pExcRoot->pAutoFilterBuffer )
381 46 : pExcRoot->pAutoFilterBuffer->Apply();
382 :
383 46 : GetWebQueryBuffer().Apply(); //! test if extant
384 46 : GetSheetProtectBuffer().Apply();
385 46 : GetDocProtectBuffer().Apply();
386 :
387 46 : ImportExcel::PostDocLoad();
388 :
389 : // Scenarien bemachen! ACHTUNG: Hier wird Tabellen-Anzahl im Dokument erhoeht!!
390 46 : if( !pD->IsClipboard() && maScenList.aEntries.size() )
391 : {
392 0 : pD->UpdateChartListenerCollection(); // references in charts must be updated
393 :
394 0 : maScenList.Apply( GetRoot() );
395 : }
396 :
397 : // read doc info (no docshell while pasting from clipboard)
398 46 : LoadDocumentProperties();
399 :
400 : // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
401 : // when formula cells are calculated, for the GETPIVOTDATA function.
402 46 : }
403 :
404 46 : void ImportExcel8::LoadDocumentProperties()
405 : {
406 : // no docshell while pasting from clipboard
407 46 : if( SfxObjectShell* pShell = GetDocShell() )
408 : {
409 : // BIFF5+ without storage is possible
410 46 : SotStorageRef xRootStrg = GetRootStorage();
411 46 : if( xRootStrg.Is() ) try
412 : {
413 46 : uno::Reference< document::XDocumentPropertiesSupplier > xDPS( pShell->GetModel(), uno::UNO_QUERY_THROW );
414 92 : uno::Reference< document::XDocumentProperties > xDocProps( xDPS->getDocumentProperties(), uno::UNO_SET_THROW );
415 92 : sfx2::LoadOlePropertySet( xDocProps, xRootStrg );
416 : }
417 0 : catch( uno::Exception& )
418 : {
419 46 : }
420 : }
421 46 : }
422 :
423 : //___________________________________________________________________
424 : // autofilter
425 :
426 5 : void ImportExcel8::FilterMode( void )
427 : {
428 : // The FilterMode record exists: if either the AutoFilter
429 : // record exists or an Advanced Filter is saved and stored
430 : // in the sheet. Thus if the FilterMode records only exists
431 : // then the latter is true..
432 10 : if( !pExcRoot->pAutoFilterBuffer ) return;
433 :
434 5 : XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
435 5 : if( pData )
436 5 : pData->SetAutoOrAdvanced();
437 : }
438 :
439 8 : void ImportExcel8::AutoFilterInfo( void )
440 : {
441 16 : if( !pExcRoot->pAutoFilterBuffer ) return;
442 :
443 8 : XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
444 8 : if( pData )
445 : {
446 8 : pData->SetAdvancedRange( NULL );
447 8 : pData->Activate();
448 : }
449 : }
450 :
451 5 : void ImportExcel8::AutoFilter( void )
452 : {
453 10 : if( !pExcRoot->pAutoFilterBuffer ) return;
454 :
455 5 : XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
456 5 : if( pData )
457 5 : pData->ReadAutoFilter( aIn );
458 : }
459 :
460 :
461 :
462 26 : XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) :
463 : ExcRoot( pRoot ),
464 : pCurrDBData(NULL),
465 : bActive( false ),
466 : bCriteria( false ),
467 26 : bAutoOrAdvanced(false)
468 : {
469 26 : aParam.nCol1 = rRange.aStart.Col();
470 26 : aParam.nRow1 = rRange.aStart.Row();
471 26 : aParam.nTab = rRange.aStart.Tab();
472 26 : aParam.nCol2 = rRange.aEnd.Col();
473 26 : aParam.nRow2 = rRange.aEnd.Row();
474 :
475 26 : aParam.bInplace = sal_True;
476 :
477 26 : }
478 :
479 1 : void XclImpAutoFilterData::CreateFromDouble( OUString& rStr, double fVal )
480 : {
481 2 : rStr += ::rtl::math::doubleToUString(fVal,
482 : rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
483 2 : ScGlobal::pLocaleData->getNumDecimalSep()[0], true);
484 1 : }
485 :
486 8 : void XclImpAutoFilterData::SetCellAttribs()
487 : {
488 8 : ScDocument& rDoc = pExcRoot->pIR->GetDoc();
489 32 : for ( SCCOL nCol = StartCol(); nCol <= EndCol(); nCol++ )
490 : {
491 24 : sal_Int16 nFlag = ((ScMergeFlagAttr*) rDoc.GetAttr( nCol, StartRow(), Tab(), ATTR_MERGE_FLAG ))->GetValue();
492 24 : rDoc.ApplyAttr( nCol, StartRow(), Tab(), ScMergeFlagAttr( nFlag | SC_MF_AUTO) );
493 : }
494 8 : }
495 :
496 8 : void XclImpAutoFilterData::InsertQueryParam()
497 : {
498 8 : if (pCurrDBData)
499 : {
500 8 : ScRange aAdvRange;
501 8 : sal_Bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange );
502 8 : if( bHasAdv )
503 0 : pExcRoot->pIR->GetDoc().CreateQueryParam( aAdvRange.aStart.Col(),
504 0 : aAdvRange.aStart.Row(), aAdvRange.aEnd.Col(), aAdvRange.aEnd.Row(),
505 0 : aAdvRange.aStart.Tab(), aParam );
506 :
507 8 : pCurrDBData->SetQueryParam( aParam );
508 8 : if( bHasAdv )
509 0 : pCurrDBData->SetAdvancedQuerySource( &aAdvRange );
510 : else
511 : {
512 8 : pCurrDBData->SetAutoFilter( sal_True );
513 8 : SetCellAttribs();
514 : }
515 : }
516 8 : }
517 :
518 4 : static void ExcelQueryToOooQuery( ScQueryEntry& rEntry )
519 : {
520 4 : if (rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL)
521 4 : return;
522 :
523 4 : String aStr = rEntry.GetQueryItem().maString;
524 4 : xub_StrLen nLen = aStr.Len();
525 4 : sal_Unicode nStart = aStr.GetChar( 0 );
526 4 : sal_Unicode nEnd = aStr.GetChar( nLen-1 );
527 4 : if( nLen >2 && nStart == '*' && nEnd == '*' )
528 : {
529 0 : aStr.Erase( nLen-1, 1 );
530 0 : aStr.Erase( 0, 1 );
531 0 : rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN;
532 : }
533 4 : else if( nLen > 1 && nStart == '*' && nEnd != '*' )
534 : {
535 0 : aStr.Erase( 0, 1 );
536 0 : rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH;
537 : }
538 4 : else if( nLen > 1 && nStart != '*' && nEnd == '*' )
539 : {
540 0 : aStr.Erase( nLen-1, 1 );
541 0 : rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH;
542 : }
543 4 : else if( nLen == 2 && nStart == '*' && nEnd == '*' )
544 : {
545 0 : aStr.Erase( 0, 1 );
546 : }
547 4 : rEntry.GetQueryItem().maString = aStr;
548 : }
549 :
550 5 : void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm )
551 : {
552 : sal_uInt16 nCol, nFlags;
553 5 : rStrm >> nCol >> nFlags;
554 :
555 5 : ScQueryConnect eConn = ::get_flagvalue( nFlags, EXC_AFFLAG_ANDORMASK, SC_OR, SC_AND );
556 5 : bool bSimple1 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE1);
557 5 : bool bSimple2 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE2);
558 5 : bool bTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10);
559 5 : bool bTopOfTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10TOP);
560 5 : bool bPercent = ::get_flag(nFlags, EXC_AFFLAG_TOP10PERC);
561 5 : sal_uInt16 nCntOfTop10 = nFlags >> 7;
562 :
563 5 : if( bTop10 )
564 : {
565 0 : ScQueryEntry& aEntry = aParam.AppendEntry();
566 0 : ScQueryEntry::Item& rItem = aEntry.GetQueryItem();
567 0 : aEntry.bDoQuery = true;
568 0 : aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
569 : aEntry.eOp = bTopOfTop10 ?
570 0 : (bPercent ? SC_TOPPERC : SC_TOPVAL) : (bPercent ? SC_BOTPERC : SC_BOTVAL);
571 0 : aEntry.eConnect = SC_AND;
572 :
573 0 : rItem.meType = ScQueryEntry::ByString;
574 0 : rItem.maString = OUString::number(nCntOfTop10);
575 :
576 0 : rStrm.Ignore(20);
577 0 : return;
578 : }
579 :
580 : sal_uInt8 nType, nOper, nBoolErr, nVal;
581 : sal_Int32 nRK;
582 : double fVal;
583 : bool bIgnore;
584 :
585 5 : sal_uInt8 nStrLen[2] = { 0, 0 };
586 15 : ScQueryEntry aEntries[2];
587 :
588 15 : for (size_t nE = 0; nE < 2; ++nE)
589 : {
590 10 : ScQueryEntry& rEntry = aEntries[nE];
591 10 : ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
592 10 : bIgnore = false;
593 :
594 10 : rStrm >> nType >> nOper;
595 10 : switch( nOper )
596 : {
597 : case EXC_AFOPER_LESS:
598 0 : rEntry.eOp = SC_LESS;
599 0 : break;
600 : case EXC_AFOPER_EQUAL:
601 6 : rEntry.eOp = SC_EQUAL;
602 6 : break;
603 : case EXC_AFOPER_LESSEQUAL:
604 0 : rEntry.eOp = SC_LESS_EQUAL;
605 0 : break;
606 : case EXC_AFOPER_GREATER:
607 0 : rEntry.eOp = SC_GREATER;
608 0 : break;
609 : case EXC_AFOPER_NOTEQUAL:
610 0 : rEntry.eOp = SC_NOT_EQUAL;
611 0 : break;
612 : case EXC_AFOPER_GREATEREQUAL:
613 0 : rEntry.eOp = SC_GREATER_EQUAL;
614 0 : break;
615 : default:
616 4 : rEntry.eOp = SC_EQUAL;
617 : }
618 :
619 10 : switch( nType )
620 : {
621 : case EXC_AFTYPE_RK:
622 0 : rStrm >> nRK;
623 0 : rStrm.Ignore( 4 );
624 : CreateFromDouble(
625 0 : rItem.maString, XclTools::GetDoubleFromRK(nRK));
626 0 : break;
627 : case EXC_AFTYPE_DOUBLE:
628 1 : rStrm >> fVal;
629 1 : CreateFromDouble(rItem.maString, fVal);
630 1 : break;
631 : case EXC_AFTYPE_STRING:
632 4 : rStrm.Ignore( 4 );
633 4 : rStrm >> nStrLen[ nE ];
634 4 : rStrm.Ignore( 3 );
635 4 : rItem.maString = OUString();
636 4 : break;
637 : case EXC_AFTYPE_BOOLERR:
638 0 : rStrm >> nBoolErr >> nVal;
639 0 : rStrm.Ignore( 6 );
640 0 : rItem.maString = OUString::number(nVal);
641 0 : bIgnore = (nBoolErr != 0);
642 0 : break;
643 : case EXC_AFTYPE_EMPTY:
644 0 : rEntry.SetQueryByEmpty();
645 0 : break;
646 : case EXC_AFTYPE_NOTEMPTY:
647 0 : rEntry.SetQueryByNonEmpty();
648 0 : break;
649 : default:
650 5 : rStrm.Ignore( 8 );
651 5 : bIgnore = true;
652 : }
653 :
654 10 : if (!bIgnore)
655 : {
656 5 : rEntry.bDoQuery = true;
657 5 : rItem.meType = ScQueryEntry::ByString;
658 5 : rEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
659 5 : rEntry.eConnect = nE ? eConn : SC_AND;
660 : }
661 : }
662 :
663 5 : if (eConn == SC_AND)
664 : {
665 15 : for (size_t nE = 0; nE < 2; ++nE)
666 : {
667 10 : if (nStrLen[nE] && aEntries[nE].bDoQuery)
668 : {
669 4 : aEntries[nE].GetQueryItem().maString = rStrm.ReadUniString(nStrLen[nE]);
670 4 : ExcelQueryToOooQuery(aEntries[nE]);
671 4 : aParam.AppendEntry() = aEntries[nE];
672 : }
673 : }
674 : }
675 : else
676 : {
677 : OSL_ASSERT(eConn == SC_OR);
678 : // Import only when both conditions are for simple equality, else
679 : // import only the 1st condition due to conflict with the ordering of
680 : // conditions. #i39464#.
681 : //
682 : // Example: Let A1 be a condition of column A, and B1 and B2
683 : // conditions of column B, connected with OR. Excel performs 'A1 AND
684 : // (B1 OR B2)' in this case, but Calc would do '(A1 AND B1) OR B2'
685 : // instead.
686 :
687 0 : if (bSimple1 && bSimple2 && nStrLen[0] && nStrLen[1])
688 : {
689 : // Two simple OR'ed equal conditions. We can import this correctly.
690 0 : ScQueryEntry& rEntry = aParam.AppendEntry();
691 0 : rEntry.bDoQuery = true;
692 0 : rEntry.eOp = SC_EQUAL;
693 0 : rEntry.eConnect = SC_AND;
694 0 : ScQueryEntry::QueryItemsType aItems;
695 0 : aItems.reserve(2);
696 0 : ScQueryEntry::Item aItem1, aItem2;
697 0 : aItem1.maString = rStrm.ReadUniString(nStrLen[0]);
698 0 : aItem1.meType = ScQueryEntry::ByString;
699 0 : aItem2.maString = rStrm.ReadUniString(nStrLen[1]);
700 0 : aItem2.meType = ScQueryEntry::ByString;
701 0 : aItems.push_back(aItem1);
702 0 : aItems.push_back(aItem2);
703 0 : rEntry.GetQueryItems().swap(aItems);
704 : }
705 0 : else if (nStrLen[0] && aEntries[0].bDoQuery)
706 : {
707 : // Due to conflict, we can import only the first condition.
708 0 : aEntries[0].GetQueryItem().maString = rStrm.ReadUniString(nStrLen[0]);
709 0 : ExcelQueryToOooQuery(aEntries[0]);
710 0 : aParam.AppendEntry() = aEntries[0];
711 : }
712 15 : }
713 : }
714 :
715 8 : void XclImpAutoFilterData::SetAdvancedRange( const ScRange* pRange )
716 : {
717 8 : if (pRange)
718 : {
719 0 : aCriteriaRange = *pRange;
720 0 : bCriteria = true;
721 : }
722 : else
723 8 : bCriteria = false;
724 8 : }
725 :
726 0 : void XclImpAutoFilterData::SetExtractPos( const ScAddress& rAddr )
727 : {
728 0 : aParam.nDestCol = rAddr.Col();
729 0 : aParam.nDestRow = rAddr.Row();
730 0 : aParam.nDestTab = rAddr.Tab();
731 0 : aParam.bInplace = false;
732 0 : aParam.bDestPers = sal_True;
733 0 : }
734 :
735 26 : void XclImpAutoFilterData::Apply()
736 : {
737 26 : CreateScDBData();
738 :
739 26 : if( bActive )
740 : {
741 8 : InsertQueryParam();
742 :
743 : // #i38093# rows hidden by filter need extra flag, but CR_FILTERED is not set here yet
744 : // SCROW nRow1 = StartRow();
745 : // SCROW nRow2 = EndRow();
746 : // size_t nRows = nRow2 - nRow1 + 1;
747 : // boost::scoped_array<sal_uInt8> pFlags( new sal_uInt8[nRows]);
748 : // pExcRoot->pDoc->GetRowFlagsArray( Tab()).FillDataArray( nRow1, nRow2,
749 : // pFlags.get());
750 : // for (size_t j=0; j<nRows; ++j)
751 : // {
752 : // if ((pFlags[j] & CR_HIDDEN) && !(pFlags[j] & CR_FILTERED))
753 : // pExcRoot->pDoc->SetRowFlags( nRow1 + j, Tab(),
754 : // pFlags[j] | CR_FILTERED );
755 : // }
756 : }
757 26 : }
758 :
759 26 : void XclImpAutoFilterData::CreateScDBData()
760 : {
761 :
762 : // Create the ScDBData() object if the AutoFilter is activated
763 : // or if we need to create the Advanced Filter.
764 26 : if( bActive || bCriteria)
765 : {
766 8 : ScDocument* pDoc = pExcRoot->pIR->GetDocPtr();
767 8 : String aNewName = OUString(STR_DB_LOCAL_NONAME);
768 8 : pCurrDBData = new ScDBData(aNewName , Tab(),
769 16 : StartCol(),StartRow(), EndCol(),EndRow() );
770 8 : if(bCriteria)
771 : {
772 0 : EnableRemoveFilter();
773 :
774 0 : pCurrDBData->SetQueryParam( aParam );
775 0 : pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange);
776 : }
777 : else
778 8 : pCurrDBData->SetAdvancedQuerySource(NULL);
779 8 : pDoc->SetAnonymousDBData(Tab(), pCurrDBData);
780 : }
781 :
782 26 : }
783 :
784 0 : void XclImpAutoFilterData::EnableRemoveFilter()
785 : {
786 : // only if this is a saved Advanced filter
787 0 : if( !bActive && bAutoOrAdvanced )
788 : {
789 0 : ScQueryEntry& aEntry = aParam.AppendEntry();
790 0 : aEntry.bDoQuery = true;
791 : }
792 :
793 : // TBD: force the automatic activation of the
794 : // "Remove Filter" by setting a virtual mouse click
795 : // inside the advanced range
796 0 : }
797 :
798 26 : void XclImpAutoFilterBuffer::Insert( RootData* pRoot, const ScRange& rRange)
799 : {
800 26 : if( !GetByTab( rRange.aStart.Tab() ) )
801 26 : maFilters.push_back( new XclImpAutoFilterData( pRoot, rRange) );
802 26 : }
803 :
804 0 : void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange& rRange )
805 : {
806 0 : XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
807 0 : if( pData )
808 0 : pData->SetAdvancedRange( &rRange );
809 0 : }
810 :
811 0 : void XclImpAutoFilterBuffer::AddExtractPos( const ScRange& rRange )
812 : {
813 0 : XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
814 0 : if( pData )
815 0 : pData->SetExtractPos( rRange.aStart );
816 0 : }
817 :
818 46 : void XclImpAutoFilterBuffer::Apply()
819 : {
820 : std::for_each(maFilters.begin(),maFilters.end(),
821 46 : boost::bind(&XclImpAutoFilterData::Apply,_1));
822 46 : }
823 :
824 200 : XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab )
825 : {
826 200 : boost::ptr_vector<XclImpAutoFilterData>::iterator it;
827 419 : for( it = maFilters.begin(); it != maFilters.end(); ++it )
828 : {
829 263 : if( it->Tab() == nTab )
830 44 : return const_cast<XclImpAutoFilterData*>(&(*it));
831 : }
832 156 : return NULL;
833 15 : }
834 :
835 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|