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 <unotools/fltrcfg.hxx>
27 :
28 : #include <vcl/wmf.hxx>
29 :
30 : #include <editeng/eeitem.hxx>
31 :
32 : #include <sfx2/docfile.hxx>
33 : #include <sfx2/objsh.hxx>
34 : #include <sfx2/request.hxx>
35 : #include <sfx2/app.hxx>
36 : #include <sfx2/docinf.hxx>
37 : #include <sfx2/frame.hxx>
38 :
39 : #include <editeng/brushitem.hxx>
40 : #include <editeng/editdata.hxx>
41 : #include <editeng/editeng.hxx>
42 : #include <editeng/editobj.hxx>
43 : #include <editeng/editstat.hxx>
44 : #include <editeng/colritem.hxx>
45 : #include <editeng/udlnitem.hxx>
46 : #include <editeng/wghtitem.hxx>
47 : #include <editeng/postitem.hxx>
48 : #include <editeng/crossedoutitem.hxx>
49 : #include <editeng/flditem.hxx>
50 : #include <svx/xflclit.hxx>
51 :
52 : #include <vcl/graph.hxx>
53 : #include <vcl/bmpacc.hxx>
54 : #include <sot/exchange.hxx>
55 :
56 : #include <svl/stritem.hxx>
57 : #include "svl/sharedstringpool.hxx"
58 :
59 : #include <rtl/math.hxx>
60 : #include <rtl/ustring.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 0 : 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, std::exception) SAL_OVERRIDE { return cppu::UnoType<container::XIndexContainer>::get(); }
124 0 : virtual sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
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, std::exception) SAL_OVERRIDE
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, std::exception) SAL_OVERRIDE
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 0 : virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
149 : {
150 0 : ::osl::MutexGuard aGuard( m_aMutex );
151 0 : 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, std::exception) SAL_OVERRIDE
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, std::exception) SAL_OVERRIDE
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, std::exception) SAL_OVERRIDE
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 :
191 : namespace {
192 :
193 : /** Future Record Type header.
194 : @return whether read rt matches nRecordID
195 : */
196 0 : bool readFrtHeader( XclImpStream& rStrm, sal_uInt16 nRecordID )
197 : {
198 0 : sal_uInt16 nRt = rStrm.ReaduInt16();
199 0 : rStrm.Ignore(10); // grbitFrt (2 bytes) and reserved (8 bytes)
200 0 : return nRt == nRecordID;
201 : }
202 :
203 : }
204 :
205 :
206 0 : ImportExcel8::ImportExcel8( XclImpRootData& rImpData, SvStream& rStrm ) :
207 0 : ImportExcel( rImpData, rStrm )
208 : {
209 : // replace BIFF2-BIFF5 formula importer with BIFF8 formula importer
210 0 : delete pFormConv;
211 0 : pFormConv = pExcRoot->pFmlaConverter = new ExcelToSc8( GetRoot() );
212 0 : }
213 :
214 :
215 0 : ImportExcel8::~ImportExcel8()
216 : {
217 0 : }
218 :
219 :
220 0 : void ImportExcel8::Calccount( void )
221 : {
222 0 : ScDocOptions aOpt = pD->GetDocOptions();
223 0 : aOpt.SetIterCount( aIn.ReaduInt16() );
224 0 : pD->SetDocOptions( aOpt );
225 0 : }
226 :
227 :
228 0 : void ImportExcel8::Precision( void )
229 : {
230 0 : ScDocOptions aOpt = pD->GetDocOptions();
231 0 : aOpt.SetCalcAsShown( aIn.ReaduInt16() == 0 );
232 0 : pD->SetDocOptions( aOpt );
233 0 : }
234 :
235 :
236 0 : void ImportExcel8::Delta( void )
237 : {
238 0 : ScDocOptions aOpt = pD->GetDocOptions();
239 0 : aOpt.SetIterEps( aIn.ReadDouble() );
240 0 : pD->SetDocOptions( aOpt );
241 0 : }
242 :
243 :
244 0 : void ImportExcel8::Iteration( void )
245 : {
246 0 : ScDocOptions aOpt = pD->GetDocOptions();
247 0 : aOpt.SetIter( aIn.ReaduInt16() == 1 );
248 0 : pD->SetDocOptions( aOpt );
249 0 : }
250 :
251 :
252 0 : void ImportExcel8::Boundsheet( void )
253 : {
254 : sal_uInt8 nLen;
255 : sal_uInt16 nGrbit;
256 :
257 0 : aIn.DisableDecryption();
258 0 : maSheetOffsets.push_back( aIn.ReaduInt32() );
259 0 : aIn.EnableDecryption();
260 0 : aIn >> nGrbit >> nLen;
261 :
262 0 : OUString aName( aIn.ReadUniString( nLen ) );
263 0 : GetTabInfo().AppendXclTabName( aName, nBdshtTab );
264 :
265 0 : SCTAB nScTab = static_cast< SCTAB >( nBdshtTab );
266 0 : if( nScTab > 0 )
267 : {
268 : OSL_ENSURE( !pD->HasTable( nScTab ), "ImportExcel8::Boundsheet - sheet exists already" );
269 0 : pD->MakeTable( nScTab );
270 : }
271 :
272 0 : if( ( nGrbit & 0x0001 ) || ( nGrbit & 0x0002 ) )
273 0 : pD->SetVisible( nScTab, false );
274 :
275 0 : if( !pD->RenameTab( nScTab, aName ) )
276 : {
277 0 : pD->CreateValidTabName( aName );
278 0 : pD->RenameTab( nScTab, aName );
279 : }
280 :
281 0 : nBdshtTab++;
282 0 : }
283 :
284 :
285 0 : void ImportExcel8::Scenman( void )
286 : {
287 : sal_uInt16 nLastDispl;
288 :
289 0 : aIn.Ignore( 4 );
290 0 : aIn >> nLastDispl;
291 :
292 0 : maScenList.nLastScenario = nLastDispl;
293 0 : }
294 :
295 :
296 0 : void ImportExcel8::Scenario( void )
297 : {
298 0 : maScenList.aEntries.push_back( new ExcScenario( aIn, *pExcRoot ) );
299 0 : }
300 :
301 :
302 0 : void ImportExcel8::Labelsst( void )
303 : {
304 0 : XclAddress aXclPos;
305 : sal_uInt16 nXF;
306 : sal_uInt32 nSst;
307 :
308 0 : aIn >> aXclPos >> nXF >> nSst;
309 :
310 0 : ScAddress aScPos( ScAddress::UNINITIALIZED );
311 0 : if( GetAddressConverter().ConvertAddress( aScPos, aXclPos, GetCurrScTab(), true ) )
312 : {
313 0 : GetXFRangeBuffer().SetXF( aScPos, nXF );
314 0 : const XclImpString* pXclStr = GetSst().GetString(nSst);
315 0 : if (pXclStr)
316 0 : XclImpStringHelper::SetToDocument(GetDocImport(), aScPos, *this, *pXclStr, nXF);
317 : }
318 0 : }
319 :
320 :
321 0 : void ImportExcel8::FeatHdr( void )
322 : {
323 0 : if (!readFrtHeader( aIn, 0x0867))
324 0 : return;
325 :
326 : // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
327 : // EXC_ISFFACTOID.
328 0 : sal_uInt16 nFeatureType = aIn.ReaduInt16();
329 0 : if (nFeatureType != EXC_ISFPROTECTION)
330 : // We currently only support import of enhanced protection data.
331 0 : return;
332 :
333 0 : aIn.Ignore(1); // always 1
334 :
335 0 : GetSheetProtectBuffer().ReadOptions( aIn, GetCurrScTab() );
336 : }
337 :
338 :
339 0 : void ImportExcel8::Feat( void )
340 : {
341 0 : if (!readFrtHeader( aIn, 0x0868))
342 0 : return;
343 :
344 : // Feature type (isf) can be EXC_ISFPROTECTION, EXC_ISFFEC2 or
345 : // EXC_ISFFACTOID.
346 0 : sal_uInt16 nFeatureType = aIn.ReaduInt16();
347 0 : if (nFeatureType != EXC_ISFPROTECTION)
348 : // We currently only support import of enhanced protection data.
349 0 : return;
350 :
351 0 : aIn.Ignore(5); // reserved1 (1 byte) and reserved2 (4 bytes)
352 :
353 0 : sal_uInt16 nCref = aIn.ReaduInt16(); // number of ref elements
354 0 : aIn.Ignore(4); // size if EXC_ISFFEC2, else 0 and to be ignored
355 0 : aIn.Ignore(2); // reserved3 (2 bytes)
356 :
357 0 : ScEnhancedProtection aProt;
358 0 : if (nCref)
359 : {
360 0 : XclRangeList aRefs;
361 0 : aRefs.Read( aIn, true, nCref);
362 0 : if (!aRefs.empty())
363 : {
364 0 : aProt.maRangeList = new ScRangeList;
365 0 : GetAddressConverter().ConvertRangeList( *aProt.maRangeList, aRefs, GetCurrScTab(), false);
366 0 : }
367 : }
368 :
369 : // FeatProtection structure follows in record.
370 :
371 0 : aProt.mnAreserved = aIn.ReaduInt32();
372 0 : aProt.mnPasswordVerifier = aIn.ReaduInt32();
373 0 : aProt.maTitle = aIn.ReadUniString();
374 0 : if ((aProt.mnAreserved & 0x00000001) == 0x00000001)
375 : {
376 0 : sal_uInt32 nCbSD = aIn.ReaduInt32();
377 : // TODO: could here be some sanity check applied to not allocate 4GB?
378 0 : aProt.maSecurityDescriptor.resize( nCbSD);
379 0 : sal_Size nRead = aIn.Read( &aProt.maSecurityDescriptor.front(), nCbSD);
380 0 : if (nRead < nCbSD)
381 0 : aProt.maSecurityDescriptor.resize( nRead);
382 : }
383 :
384 0 : GetSheetProtectBuffer().AppendEnhancedProtection( aProt, GetCurrScTab() );
385 : }
386 :
387 :
388 0 : void ImportExcel8::ReadBasic( void )
389 : {
390 0 : SfxObjectShell* pShell = GetDocShell();
391 0 : SotStorageRef xRootStrg = GetRootStorage();
392 0 : const SvtFilterOptions& rFilterOpt = SvtFilterOptions::Get();
393 0 : if( pShell && xRootStrg.Is() ) try
394 : {
395 : // #FIXME need to get rid of this, we can also do this from within oox
396 : // via the "ooo.vba.VBAGlobals" service
397 0 : if( ( rFilterOpt.IsLoadExcelBasicCode() ||
398 0 : rFilterOpt.IsLoadExcelBasicStorage() ) &&
399 0 : rFilterOpt.IsLoadExcelBasicExecutable() )
400 : {
401 : // see if we have the XCB stream
402 0 : SvStorageStreamRef xXCB = xRootStrg->OpenSotStream( OUString("XCB"), STREAM_STD_READ | STREAM_NOCREATE );
403 0 : if ( xXCB.Is()|| SVSTREAM_OK == xXCB->GetError() )
404 : {
405 0 : ScCTBWrapper wrapper;
406 0 : if ( wrapper.Read( *xXCB ) )
407 : {
408 : #if OSL_DEBUG_LEVEL > 1
409 : wrapper.Print( stderr );
410 : #endif
411 0 : wrapper.ImportCustomToolBar( *pShell );
412 0 : }
413 0 : }
414 : }
415 : try
416 : {
417 0 : uno::Reference< uno::XComponentContext > aCtx( ::comphelper::getProcessComponentContext() );
418 0 : SfxMedium& rMedium = GetMedium();
419 0 : uno::Reference< io::XInputStream > xIn = rMedium.GetInputStream();
420 0 : oox::ole::OleStorage root( aCtx, xIn, false );
421 0 : oox::StorageRef vbaStg = root.openSubStorage( "_VBA_PROJECT_CUR", false );
422 0 : if ( vbaStg.get() )
423 : {
424 0 : oox::ole::VbaProject aVbaPrj( aCtx, pShell->GetModel(), "Calc" );
425 : // collect names of embedded form controls, as specified in the VBA project
426 0 : uno::Reference< container::XNameContainer > xOleNameOverrideSink( new OleNameOverrideContainer );
427 0 : aVbaPrj.setOleOverridesSink( xOleNameOverrideSink );
428 0 : aVbaPrj.importVbaProject( *vbaStg );
429 0 : GetObjectManager().SetOleNameOverrideInfo( xOleNameOverrideSink );
430 0 : }
431 : }
432 0 : catch( uno::Exception& )
433 : {
434 : }
435 : }
436 0 : catch( uno::Exception& )
437 : {
438 0 : }
439 0 : }
440 :
441 :
442 0 : void ImportExcel8::EndSheet( void )
443 : {
444 0 : ImportExcel::EndSheet();
445 0 : GetCondFormatManager().Apply();
446 0 : GetValidationManager().Apply();
447 0 : }
448 :
449 :
450 0 : void ImportExcel8::PostDocLoad( void )
451 : {
452 : #ifndef DISABLE_SCRIPTING
453 : // reading basic has been delayed until sheet objects (codenames etc.) are read
454 0 : if( HasBasic() )
455 0 : ReadBasic();
456 : #endif
457 : // #i11776# filtered ranges before outlines and hidden rows
458 0 : if( pExcRoot->pAutoFilterBuffer )
459 0 : pExcRoot->pAutoFilterBuffer->Apply();
460 :
461 0 : GetWebQueryBuffer().Apply(); //! test if extant
462 0 : GetSheetProtectBuffer().Apply();
463 0 : GetDocProtectBuffer().Apply();
464 :
465 0 : ImportExcel::PostDocLoad();
466 :
467 : // Scenarien bemachen! ACHTUNG: Hier wird Tabellen-Anzahl im Dokument erhoeht!!
468 0 : if( !pD->IsClipboard() && maScenList.aEntries.size() )
469 : {
470 0 : pD->UpdateChartListenerCollection(); // references in charts must be updated
471 :
472 0 : maScenList.Apply( GetRoot() );
473 : }
474 :
475 : // read doc info (no docshell while pasting from clipboard)
476 0 : LoadDocumentProperties();
477 :
478 : // #i45843# Pivot tables are now handled outside of PostDocLoad, so they are available
479 : // when formula cells are calculated, for the GETPIVOTDATA function.
480 0 : }
481 :
482 0 : void ImportExcel8::LoadDocumentProperties()
483 : {
484 : // no docshell while pasting from clipboard
485 0 : if( SfxObjectShell* pShell = GetDocShell() )
486 : {
487 : // BIFF5+ without storage is possible
488 0 : SotStorageRef xRootStrg = GetRootStorage();
489 0 : if( xRootStrg.Is() ) try
490 : {
491 0 : uno::Reference< document::XDocumentPropertiesSupplier > xDPS( pShell->GetModel(), uno::UNO_QUERY_THROW );
492 0 : uno::Reference< document::XDocumentProperties > xDocProps( xDPS->getDocumentProperties(), uno::UNO_SET_THROW );
493 0 : sfx2::LoadOlePropertySet( xDocProps, xRootStrg );
494 : }
495 0 : catch( uno::Exception& )
496 : {
497 0 : }
498 : }
499 0 : }
500 :
501 :
502 : // autofilter
503 :
504 0 : void ImportExcel8::FilterMode( void )
505 : {
506 : // The FilterMode record exists: if either the AutoFilter
507 : // record exists or an Advanced Filter is saved and stored
508 : // in the sheet. Thus if the FilterMode records only exists
509 : // then the latter is true..
510 0 : if( !pExcRoot->pAutoFilterBuffer ) return;
511 :
512 0 : XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
513 0 : if( pData )
514 0 : pData->SetAutoOrAdvanced();
515 : }
516 :
517 0 : void ImportExcel8::AutoFilterInfo( void )
518 : {
519 0 : if( !pExcRoot->pAutoFilterBuffer ) return;
520 :
521 0 : XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
522 0 : if( pData )
523 : {
524 0 : pData->SetAdvancedRange( NULL );
525 0 : pData->Activate();
526 : }
527 : }
528 :
529 0 : void ImportExcel8::AutoFilter( void )
530 : {
531 0 : if( !pExcRoot->pAutoFilterBuffer ) return;
532 :
533 0 : XclImpAutoFilterData* pData = pExcRoot->pAutoFilterBuffer->GetByTab( GetCurrScTab() );
534 0 : if( pData )
535 0 : pData->ReadAutoFilter(aIn, GetDoc().GetSharedStringPool());
536 : }
537 :
538 0 : XclImpAutoFilterData::XclImpAutoFilterData( RootData* pRoot, const ScRange& rRange ) :
539 : ExcRoot( pRoot ),
540 : pCurrDBData(NULL),
541 : bActive( false ),
542 : bCriteria( false ),
543 0 : bAutoOrAdvanced(false)
544 : {
545 0 : aParam.nCol1 = rRange.aStart.Col();
546 0 : aParam.nRow1 = rRange.aStart.Row();
547 0 : aParam.nTab = rRange.aStart.Tab();
548 0 : aParam.nCol2 = rRange.aEnd.Col();
549 0 : aParam.nRow2 = rRange.aEnd.Row();
550 :
551 0 : aParam.bInplace = true;
552 :
553 0 : }
554 :
555 : namespace {
556 :
557 0 : OUString CreateFromDouble( double fVal )
558 : {
559 : return rtl::math::doubleToUString(fVal,
560 : rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
561 0 : ScGlobal::pLocaleData->getNumDecimalSep()[0], true);
562 : }
563 :
564 : }
565 :
566 0 : void XclImpAutoFilterData::SetCellAttribs()
567 : {
568 0 : ScDocument& rDoc = pExcRoot->pIR->GetDoc();
569 0 : for ( SCCOL nCol = StartCol(); nCol <= EndCol(); nCol++ )
570 : {
571 0 : sal_Int16 nFlag = ((ScMergeFlagAttr*) rDoc.GetAttr( nCol, StartRow(), Tab(), ATTR_MERGE_FLAG ))->GetValue();
572 0 : rDoc.ApplyAttr( nCol, StartRow(), Tab(), ScMergeFlagAttr( nFlag | SC_MF_AUTO) );
573 : }
574 0 : }
575 :
576 0 : void XclImpAutoFilterData::InsertQueryParam()
577 : {
578 0 : if (pCurrDBData)
579 : {
580 0 : ScRange aAdvRange;
581 0 : sal_Bool bHasAdv = pCurrDBData->GetAdvancedQuerySource( aAdvRange );
582 0 : if( bHasAdv )
583 0 : pExcRoot->pIR->GetDoc().CreateQueryParam( aAdvRange.aStart.Col(),
584 0 : aAdvRange.aStart.Row(), aAdvRange.aEnd.Col(), aAdvRange.aEnd.Row(),
585 0 : aAdvRange.aStart.Tab(), aParam );
586 :
587 0 : pCurrDBData->SetQueryParam( aParam );
588 0 : if( bHasAdv )
589 0 : pCurrDBData->SetAdvancedQuerySource( &aAdvRange );
590 : else
591 : {
592 0 : pCurrDBData->SetAutoFilter( true );
593 0 : SetCellAttribs();
594 : }
595 : }
596 0 : }
597 :
598 0 : static void ExcelQueryToOooQuery( OUString& aStr, ScQueryEntry& rEntry )
599 : {
600 0 : if (rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL)
601 0 : return;
602 :
603 0 : sal_Int32 nLen = aStr.getLength();
604 0 : sal_Unicode nStart = aStr[0];
605 0 : sal_Unicode nEnd = aStr[ nLen-1 ];
606 0 : if( nLen > 2 && nStart == '*' && nEnd == '*' )
607 : {
608 0 : aStr = aStr.copy( 1, nLen-2 );
609 0 : rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN;
610 : }
611 0 : else if( nLen > 1 && nStart == '*' && nEnd != '*' )
612 : {
613 0 : aStr = aStr.copy( 1 );
614 0 : rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH;
615 : }
616 0 : else if( nLen > 1 && nStart != '*' && nEnd == '*' )
617 : {
618 0 : aStr = aStr.copy( 0, nLen-1 );
619 0 : rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH;
620 : }
621 0 : else if( nLen == 2 && nStart == '*' && nEnd == '*' )
622 : {
623 0 : aStr = aStr.copy( 1 );
624 : }
625 : }
626 :
627 0 : void XclImpAutoFilterData::ReadAutoFilter(
628 : XclImpStream& rStrm, svl::SharedStringPool& rPool )
629 : {
630 : sal_uInt16 nCol, nFlags;
631 0 : rStrm >> nCol >> nFlags;
632 :
633 0 : ScQueryConnect eConn = ::get_flagvalue( nFlags, EXC_AFFLAG_ANDORMASK, SC_OR, SC_AND );
634 0 : bool bSimple1 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE1);
635 0 : bool bSimple2 = ::get_flag(nFlags, EXC_AFFLAG_SIMPLE2);
636 0 : bool bTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10);
637 0 : bool bTopOfTop10 = ::get_flag(nFlags, EXC_AFFLAG_TOP10TOP);
638 0 : bool bPercent = ::get_flag(nFlags, EXC_AFFLAG_TOP10PERC);
639 0 : sal_uInt16 nCntOfTop10 = nFlags >> 7;
640 :
641 0 : if( bTop10 )
642 : {
643 0 : ScQueryEntry& aEntry = aParam.AppendEntry();
644 0 : ScQueryEntry::Item& rItem = aEntry.GetQueryItem();
645 0 : aEntry.bDoQuery = true;
646 0 : aEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
647 : aEntry.eOp = bTopOfTop10 ?
648 0 : (bPercent ? SC_TOPPERC : SC_TOPVAL) : (bPercent ? SC_BOTPERC : SC_BOTVAL);
649 0 : aEntry.eConnect = SC_AND;
650 :
651 0 : rItem.meType = ScQueryEntry::ByString;
652 0 : rItem.maString = rPool.intern(OUString::number(nCntOfTop10));
653 :
654 0 : rStrm.Ignore(20);
655 0 : return;
656 : }
657 :
658 : sal_uInt8 nType, nOper, nBoolErr, nVal;
659 : sal_Int32 nRK;
660 : double fVal;
661 : bool bIgnore;
662 :
663 0 : sal_uInt8 nStrLen[2] = { 0, 0 };
664 0 : ScQueryEntry aEntries[2];
665 :
666 0 : for (size_t nE = 0; nE < 2; ++nE)
667 : {
668 0 : ScQueryEntry& rEntry = aEntries[nE];
669 0 : ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
670 0 : bIgnore = false;
671 :
672 0 : rStrm >> nType >> nOper;
673 0 : switch( nOper )
674 : {
675 : case EXC_AFOPER_LESS:
676 0 : rEntry.eOp = SC_LESS;
677 0 : break;
678 : case EXC_AFOPER_EQUAL:
679 0 : rEntry.eOp = SC_EQUAL;
680 0 : break;
681 : case EXC_AFOPER_LESSEQUAL:
682 0 : rEntry.eOp = SC_LESS_EQUAL;
683 0 : break;
684 : case EXC_AFOPER_GREATER:
685 0 : rEntry.eOp = SC_GREATER;
686 0 : break;
687 : case EXC_AFOPER_NOTEQUAL:
688 0 : rEntry.eOp = SC_NOT_EQUAL;
689 0 : break;
690 : case EXC_AFOPER_GREATEREQUAL:
691 0 : rEntry.eOp = SC_GREATER_EQUAL;
692 0 : break;
693 : default:
694 0 : rEntry.eOp = SC_EQUAL;
695 : }
696 :
697 0 : switch( nType )
698 : {
699 : case EXC_AFTYPE_RK:
700 0 : rStrm >> nRK;
701 0 : rStrm.Ignore( 4 );
702 0 : rItem.maString = rPool.intern(
703 0 : CreateFromDouble(XclTools::GetDoubleFromRK(nRK)));
704 0 : break;
705 : case EXC_AFTYPE_DOUBLE:
706 0 : rStrm >> fVal;
707 0 : rItem.maString = rPool.intern(CreateFromDouble(fVal));
708 0 : break;
709 : case EXC_AFTYPE_STRING:
710 0 : rStrm.Ignore( 4 );
711 0 : rStrm >> nStrLen[ nE ];
712 0 : rStrm.Ignore( 3 );
713 0 : rItem.maString = svl::SharedString();
714 0 : break;
715 : case EXC_AFTYPE_BOOLERR:
716 0 : rStrm >> nBoolErr >> nVal;
717 0 : rStrm.Ignore( 6 );
718 0 : rItem.maString = rPool.intern(OUString::number(nVal));
719 0 : bIgnore = (nBoolErr != 0);
720 0 : break;
721 : case EXC_AFTYPE_EMPTY:
722 0 : rEntry.SetQueryByEmpty();
723 0 : break;
724 : case EXC_AFTYPE_NOTEMPTY:
725 0 : rEntry.SetQueryByNonEmpty();
726 0 : break;
727 : default:
728 0 : rStrm.Ignore( 8 );
729 0 : bIgnore = true;
730 : }
731 :
732 0 : if (!bIgnore)
733 : {
734 0 : rEntry.bDoQuery = true;
735 0 : rItem.meType = ScQueryEntry::ByString;
736 0 : rEntry.nField = static_cast<SCCOLROW>(StartCol() + static_cast<SCCOL>(nCol));
737 0 : rEntry.eConnect = nE ? eConn : SC_AND;
738 : }
739 : }
740 :
741 0 : if (eConn == SC_AND)
742 : {
743 0 : for (size_t nE = 0; nE < 2; ++nE)
744 : {
745 0 : if (nStrLen[nE] && aEntries[nE].bDoQuery)
746 : {
747 0 : OUString aStr = rStrm.ReadUniString(nStrLen[nE]);
748 0 : ExcelQueryToOooQuery(aStr, aEntries[nE]);
749 0 : aEntries[nE].GetQueryItem().maString = rPool.intern(aStr);
750 0 : aParam.AppendEntry() = aEntries[nE];
751 : }
752 : }
753 : }
754 : else
755 : {
756 : OSL_ASSERT(eConn == SC_OR);
757 : // Import only when both conditions are for simple equality, else
758 : // import only the 1st condition due to conflict with the ordering of
759 : // conditions. #i39464#.
760 : //
761 : // Example: Let A1 be a condition of column A, and B1 and B2
762 : // conditions of column B, connected with OR. Excel performs 'A1 AND
763 : // (B1 OR B2)' in this case, but Calc would do '(A1 AND B1) OR B2'
764 : // instead.
765 :
766 0 : if (bSimple1 && bSimple2 && nStrLen[0] && nStrLen[1])
767 : {
768 : // Two simple OR'ed equal conditions. We can import this correctly.
769 0 : ScQueryEntry& rEntry = aParam.AppendEntry();
770 0 : rEntry.bDoQuery = true;
771 0 : rEntry.eOp = SC_EQUAL;
772 0 : rEntry.eConnect = SC_AND;
773 0 : ScQueryEntry::QueryItemsType aItems;
774 0 : aItems.reserve(2);
775 0 : ScQueryEntry::Item aItem1, aItem2;
776 0 : aItem1.maString = rPool.intern(rStrm.ReadUniString(nStrLen[0]));
777 0 : aItem1.meType = ScQueryEntry::ByString;
778 0 : aItem2.maString = rPool.intern(rStrm.ReadUniString(nStrLen[1]));
779 0 : aItem2.meType = ScQueryEntry::ByString;
780 0 : aItems.push_back(aItem1);
781 0 : aItems.push_back(aItem2);
782 0 : rEntry.GetQueryItems().swap(aItems);
783 : }
784 0 : else if (nStrLen[0] && aEntries[0].bDoQuery)
785 : {
786 : // Due to conflict, we can import only the first condition.
787 0 : OUString aStr = rStrm.ReadUniString(nStrLen[0]);
788 0 : ExcelQueryToOooQuery(aStr, aEntries[0]);
789 0 : aEntries[0].GetQueryItem().maString = rPool.intern(aStr);
790 0 : aParam.AppendEntry() = aEntries[0];
791 : }
792 0 : }
793 : }
794 :
795 0 : void XclImpAutoFilterData::SetAdvancedRange( const ScRange* pRange )
796 : {
797 0 : if (pRange)
798 : {
799 0 : aCriteriaRange = *pRange;
800 0 : bCriteria = true;
801 : }
802 : else
803 0 : bCriteria = false;
804 0 : }
805 :
806 0 : void XclImpAutoFilterData::SetExtractPos( const ScAddress& rAddr )
807 : {
808 0 : aParam.nDestCol = rAddr.Col();
809 0 : aParam.nDestRow = rAddr.Row();
810 0 : aParam.nDestTab = rAddr.Tab();
811 0 : aParam.bInplace = false;
812 0 : aParam.bDestPers = true;
813 0 : }
814 :
815 0 : void XclImpAutoFilterData::Apply()
816 : {
817 0 : CreateScDBData();
818 :
819 0 : if( bActive )
820 : {
821 0 : InsertQueryParam();
822 :
823 : // #i38093# rows hidden by filter need extra flag, but CR_FILTERED is not set here yet
824 : // SCROW nRow1 = StartRow();
825 : // SCROW nRow2 = EndRow();
826 : // size_t nRows = nRow2 - nRow1 + 1;
827 : // boost::scoped_array<sal_uInt8> pFlags( new sal_uInt8[nRows]);
828 : // pExcRoot->pDoc->GetRowFlagsArray( Tab()).FillDataArray( nRow1, nRow2,
829 : // pFlags.get());
830 : // for (size_t j=0; j<nRows; ++j)
831 : // {
832 : // if ((pFlags[j] & CR_HIDDEN) && !(pFlags[j] & CR_FILTERED))
833 : // pExcRoot->pDoc->SetRowFlags( nRow1 + j, Tab(),
834 : // pFlags[j] | CR_FILTERED );
835 : // }
836 : }
837 0 : }
838 :
839 0 : void XclImpAutoFilterData::CreateScDBData()
840 : {
841 :
842 : // Create the ScDBData() object if the AutoFilter is activated
843 : // or if we need to create the Advanced Filter.
844 0 : if( bActive || bCriteria)
845 : {
846 0 : ScDocument* pDoc = pExcRoot->pIR->GetDocPtr();
847 0 : OUString aNewName(STR_DB_LOCAL_NONAME);
848 0 : pCurrDBData = new ScDBData(aNewName , Tab(),
849 0 : StartCol(),StartRow(), EndCol(),EndRow() );
850 0 : if(bCriteria)
851 : {
852 0 : EnableRemoveFilter();
853 :
854 0 : pCurrDBData->SetQueryParam( aParam );
855 0 : pCurrDBData->SetAdvancedQuerySource(&aCriteriaRange);
856 : }
857 : else
858 0 : pCurrDBData->SetAdvancedQuerySource(NULL);
859 0 : pDoc->SetAnonymousDBData(Tab(), pCurrDBData);
860 : }
861 :
862 0 : }
863 :
864 0 : void XclImpAutoFilterData::EnableRemoveFilter()
865 : {
866 : // only if this is a saved Advanced filter
867 0 : if( !bActive && bAutoOrAdvanced )
868 : {
869 0 : ScQueryEntry& aEntry = aParam.AppendEntry();
870 0 : aEntry.bDoQuery = true;
871 : }
872 :
873 : // TBD: force the automatic activation of the
874 : // "Remove Filter" by setting a virtual mouse click
875 : // inside the advanced range
876 0 : }
877 :
878 0 : void XclImpAutoFilterBuffer::Insert( RootData* pRoot, const ScRange& rRange)
879 : {
880 0 : if( !GetByTab( rRange.aStart.Tab() ) )
881 0 : maFilters.push_back( new XclImpAutoFilterData( pRoot, rRange) );
882 0 : }
883 :
884 0 : void XclImpAutoFilterBuffer::AddAdvancedRange( const ScRange& rRange )
885 : {
886 0 : XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
887 0 : if( pData )
888 0 : pData->SetAdvancedRange( &rRange );
889 0 : }
890 :
891 0 : void XclImpAutoFilterBuffer::AddExtractPos( const ScRange& rRange )
892 : {
893 0 : XclImpAutoFilterData* pData = GetByTab( rRange.aStart.Tab() );
894 0 : if( pData )
895 0 : pData->SetExtractPos( rRange.aStart );
896 0 : }
897 :
898 0 : void XclImpAutoFilterBuffer::Apply()
899 : {
900 : std::for_each(maFilters.begin(),maFilters.end(),
901 0 : boost::bind(&XclImpAutoFilterData::Apply,_1));
902 0 : }
903 :
904 0 : XclImpAutoFilterData* XclImpAutoFilterBuffer::GetByTab( SCTAB nTab )
905 : {
906 0 : boost::ptr_vector<XclImpAutoFilterData>::iterator it;
907 0 : for( it = maFilters.begin(); it != maFilters.end(); ++it )
908 : {
909 0 : if( it->Tab() == nTab )
910 0 : return const_cast<XclImpAutoFilterData*>(&(*it));
911 : }
912 0 : return NULL;
913 0 : }
914 :
915 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|