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