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