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 "workbookfragment.hxx"
21 :
22 : #include <com/sun/star/table/CellAddress.hpp>
23 : #include "oox/core/filterbase.hxx"
24 : #include "oox/drawingml/themefragmenthandler.hxx"
25 : #include "oox/helper/attributelist.hxx"
26 : #include "oox/helper/progressbar.hxx"
27 : #include "oox/helper/propertyset.hxx"
28 : #include "oox/ole/olestorage.hxx"
29 : #include "vcl/msgbox.hxx"
30 :
31 : #include "biffinputstream.hxx"
32 : #include "chartsheetfragment.hxx"
33 : #include "connectionsfragment.hxx"
34 : #include "externallinkbuffer.hxx"
35 : #include "externallinkfragment.hxx"
36 : #include "pivotcachebuffer.hxx"
37 : #include "sharedstringsbuffer.hxx"
38 : #include "sharedstringsfragment.hxx"
39 : #include "stylesfragment.hxx"
40 : #include "tablebuffer.hxx"
41 : #include "themebuffer.hxx"
42 : #include "viewsettings.hxx"
43 : #include "workbooksettings.hxx"
44 : #include "worksheetbuffer.hxx"
45 : #include "worksheetfragment.hxx"
46 :
47 : #include "document.hxx"
48 : #include "docsh.hxx"
49 : #include "globstr.hrc"
50 : #include "calcconfig.hxx"
51 :
52 : #include <comphelper/processfactory.hxx>
53 : #include <officecfg/Office/Calc.hxx>
54 : #include "oox/ole/vbaproject.hxx"
55 :
56 : namespace oox {
57 : namespace xls {
58 :
59 : // ============================================================================
60 :
61 : using namespace ::com::sun::star::io;
62 : using namespace ::com::sun::star::table;
63 : using namespace ::com::sun::star::uno;
64 : using namespace ::com::sun::star::sheet;
65 : using namespace ::oox::core;
66 :
67 : using ::oox::drawingml::ThemeFragmentHandler;
68 :
69 : // ============================================================================
70 :
71 : namespace {
72 :
73 : const double PROGRESS_LENGTH_GLOBALS = 0.1; /// 10% of progress bar for globals import.
74 :
75 : } // namespace
76 :
77 : // ============================================================================
78 :
79 21 : WorkbookFragment::WorkbookFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
80 21 : WorkbookFragmentBase( rHelper, rFragmentPath )
81 : {
82 21 : }
83 :
84 219 : ContextHandlerRef WorkbookFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
85 : {
86 219 : switch( getCurrentElement() )
87 : {
88 : case XML_ROOT_CONTEXT:
89 21 : if( nElement == XLS_TOKEN( workbook ) ) return this;
90 0 : break;
91 :
92 : case XLS_TOKEN( workbook ):
93 123 : switch( nElement )
94 : {
95 : case XLS_TOKEN( sheets ):
96 : case XLS_TOKEN( bookViews ):
97 : case XLS_TOKEN( externalReferences ):
98 : case XLS_TOKEN( definedNames ):
99 44 : case XLS_TOKEN( pivotCaches ): return this;
100 :
101 0 : case XLS_TOKEN( fileSharing ): getWorkbookSettings().importFileSharing( rAttribs ); break;
102 21 : case XLS_TOKEN( workbookPr ): getWorkbookSettings().importWorkbookPr( rAttribs ); break;
103 21 : case XLS_TOKEN( calcPr ): getWorkbookSettings().importCalcPr( rAttribs ); break;
104 0 : case XLS_TOKEN( oleSize ): getViewSettings().importOleSize( rAttribs ); break;
105 : }
106 79 : break;
107 :
108 : case XLS_TOKEN( sheets ):
109 43 : if( nElement == XLS_TOKEN( sheet ) ) getWorksheets().importSheet( rAttribs );
110 43 : break;
111 : case XLS_TOKEN( bookViews ):
112 21 : if( nElement == XLS_TOKEN( workbookView ) ) getViewSettings().importWorkbookView( rAttribs );
113 21 : break;
114 : case XLS_TOKEN( externalReferences ):
115 0 : if( nElement == XLS_TOKEN( externalReference ) ) importExternalReference( rAttribs );
116 0 : break;
117 : case XLS_TOKEN( definedNames ):
118 11 : if( nElement == XLS_TOKEN( definedName ) ) { importDefinedName( rAttribs ); return this; } // collect formula
119 0 : break;
120 : case XLS_TOKEN( pivotCaches ):
121 0 : if( nElement == XLS_TOKEN( pivotCache ) ) importPivotCache( rAttribs );
122 0 : break;
123 : }
124 143 : return 0;
125 : }
126 :
127 11 : void WorkbookFragment::onCharacters( const OUString& rChars )
128 : {
129 11 : if( isCurrentElement( XLS_TOKEN( definedName ) ) && mxCurrName.get() )
130 11 : mxCurrName->setFormula( rChars );
131 11 : }
132 :
133 0 : ContextHandlerRef WorkbookFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
134 : {
135 0 : switch( getCurrentElement() )
136 : {
137 : case XML_ROOT_CONTEXT:
138 0 : if( nRecId == BIFF12_ID_WORKBOOK ) return this;
139 0 : break;
140 :
141 : case BIFF12_ID_WORKBOOK:
142 0 : switch( nRecId )
143 : {
144 : case BIFF12_ID_SHEETS:
145 : case BIFF12_ID_BOOKVIEWS:
146 : case BIFF12_ID_EXTERNALREFS:
147 0 : case BIFF12_ID_PIVOTCACHES: return this;
148 :
149 0 : case BIFF12_ID_FILESHARING: getWorkbookSettings().importFileSharing( rStrm ); break;
150 0 : case BIFF12_ID_WORKBOOKPR: getWorkbookSettings().importWorkbookPr( rStrm ); break;
151 0 : case BIFF12_ID_CALCPR: getWorkbookSettings().importCalcPr( rStrm ); break;
152 0 : case BIFF12_ID_OLESIZE: getViewSettings().importOleSize( rStrm ); break;
153 0 : case BIFF12_ID_DEFINEDNAME: getDefinedNames().importDefinedName( rStrm ); break;
154 : }
155 0 : break;
156 :
157 : case BIFF12_ID_SHEETS:
158 0 : if( nRecId == BIFF12_ID_SHEET ) getWorksheets().importSheet( rStrm );
159 0 : break;
160 : case BIFF12_ID_BOOKVIEWS:
161 0 : if( nRecId == BIFF12_ID_WORKBOOKVIEW ) getViewSettings().importWorkbookView( rStrm );
162 0 : break;
163 :
164 : case BIFF12_ID_EXTERNALREFS:
165 0 : switch( nRecId )
166 : {
167 0 : case BIFF12_ID_EXTERNALREF: importExternalRef( rStrm ); break;
168 0 : case BIFF12_ID_EXTERNALSELF: getExternalLinks().importExternalSelf( rStrm ); break;
169 0 : case BIFF12_ID_EXTERNALSAME: getExternalLinks().importExternalSame( rStrm ); break;
170 0 : case BIFF12_ID_EXTERNALADDIN: getExternalLinks().importExternalAddin( rStrm ); break;
171 0 : case BIFF12_ID_EXTERNALSHEETS: getExternalLinks().importExternalSheets( rStrm ); break;
172 : }
173 0 : break;
174 :
175 : case BIFF12_ID_PIVOTCACHES:
176 0 : if( nRecId == BIFF12_ID_PIVOTCACHE ) importPivotCache( rStrm );
177 : }
178 0 : return 0;
179 : }
180 :
181 0 : const RecordInfo* WorkbookFragment::getRecordInfos() const
182 : {
183 : static const RecordInfo spRecInfos[] =
184 : {
185 : { BIFF12_ID_BOOKVIEWS, BIFF12_ID_BOOKVIEWS + 1 },
186 : { BIFF12_ID_EXTERNALREFS, BIFF12_ID_EXTERNALREFS + 1 },
187 : { BIFF12_ID_FUNCTIONGROUPS, BIFF12_ID_FUNCTIONGROUPS + 2 },
188 : { BIFF12_ID_PIVOTCACHE, BIFF12_ID_PIVOTCACHE + 1 },
189 : { BIFF12_ID_PIVOTCACHES, BIFF12_ID_PIVOTCACHES + 1 },
190 : { BIFF12_ID_SHEETS, BIFF12_ID_SHEETS + 1 },
191 : { BIFF12_ID_WORKBOOK, BIFF12_ID_WORKBOOK + 1 },
192 : { -1, -1 }
193 : };
194 0 : return spRecInfos;
195 : }
196 :
197 21 : void WorkbookFragment::finalizeImport()
198 : {
199 21 : ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
200 :
201 : // read the theme substream
202 42 : OUString aThemeFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "theme" ) );
203 21 : if( !aThemeFragmentPath.isEmpty() )
204 7 : importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme() ) );
205 21 : xGlobalSegment->setPosition( 0.25 );
206 :
207 : // read the styles substream (requires finalized theme buffer)
208 42 : OUString aStylesFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "styles" ) );
209 21 : if( !aStylesFragmentPath.isEmpty() )
210 21 : importOoxFragment( new StylesFragment( *this, aStylesFragmentPath ) );
211 21 : xGlobalSegment->setPosition( 0.5 );
212 :
213 : // read the shared string table substream (requires finalized styles buffer)
214 42 : OUString aSstFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "sharedStrings" ) );
215 21 : if( !aSstFragmentPath.isEmpty() )
216 11 : importOoxFragment( new SharedStringsFragment( *this, aSstFragmentPath ) );
217 21 : xGlobalSegment->setPosition( 0.75 );
218 :
219 : // read the connections substream
220 42 : OUString aConnFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "connections" ) );
221 21 : if( !aConnFragmentPath.isEmpty() )
222 0 : importOoxFragment( new ConnectionsFragment( *this, aConnFragmentPath ) );
223 21 : xGlobalSegment->setPosition( 1.0 );
224 :
225 :
226 : /* Create fragments for all sheets, before importing them. Needed to do
227 : some preprocessing in the fragment constructors, e.g. loading the table
228 : fragments for all sheets that are needed before the cell formulas are
229 : loaded. Additionally, the instances of the WorkbookGlobals structures
230 : have to be stored for every sheet. */
231 : typedef ::std::pair< WorksheetGlobalsRef, FragmentHandlerRef > SheetFragmentHandler;
232 : typedef ::std::vector< SheetFragmentHandler > SheetFragmentVector;
233 42 : SheetFragmentVector aSheetFragments;
234 42 : std::vector<WorksheetHelper*> maHelpers;
235 21 : WorksheetBuffer& rWorksheets = getWorksheets();
236 21 : sal_Int32 nWorksheetCount = rWorksheets.getWorksheetCount();
237 64 : for( sal_Int32 nWorksheet = 0; nWorksheet < nWorksheetCount; ++nWorksheet )
238 : {
239 43 : sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet );
240 43 : const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getWorksheetRelId( nWorksheet ) );
241 43 : if( (nCalcSheet >= 0) && pRelation )
242 : {
243 : // get fragment path of the sheet
244 43 : OUString aFragmentPath = getFragmentPathFromRelation( *pRelation );
245 : OSL_ENSURE( !aFragmentPath.isEmpty(), "WorkbookFragment::finalizeImport - cannot access sheet fragment" );
246 43 : if( !aFragmentPath.isEmpty() )
247 : {
248 : // leave space for formula processing ( calcuate the segments as
249 : // if there is an extra sheet )
250 43 : double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - ( nWorksheet - 1) );
251 43 : ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength );
252 :
253 : // get the sheet type according to the relations type
254 43 : WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET;
255 43 : if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "worksheet" ) )
256 43 : eSheetType = SHEETTYPE_WORKSHEET;
257 0 : else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "chartsheet" ) )
258 0 : eSheetType = SHEETTYPE_CHARTSHEET;
259 0 : else if( (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlMacrosheet" )) ||
260 0 : (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlIntlMacrosheet" )) )
261 0 : eSheetType = SHEETTYPE_MACROSHEET;
262 0 : else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "dialogsheet" ) )
263 0 : eSheetType = SHEETTYPE_DIALOGSHEET;
264 : OSL_ENSURE( eSheetType != SHEETTYPE_EMPTYSHEET, "WorkbookFragment::finalizeImport - unknown sheet type" );
265 43 : if( eSheetType != SHEETTYPE_EMPTYSHEET )
266 : {
267 : // create the WorksheetGlobals object
268 43 : WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetSegment, eSheetType, nCalcSheet );
269 : OSL_ENSURE( xSheetGlob.get(), "WorkbookFragment::finalizeImport - missing sheet in document" );
270 43 : if( xSheetGlob.get() )
271 : {
272 : // create the sheet fragment handler
273 43 : ::rtl::Reference< WorksheetFragmentBase > xFragment;
274 43 : switch( eSheetType )
275 : {
276 : case SHEETTYPE_WORKSHEET:
277 : case SHEETTYPE_MACROSHEET:
278 : case SHEETTYPE_DIALOGSHEET:
279 43 : xFragment.set( new WorksheetFragment( *xSheetGlob, aFragmentPath ) );
280 43 : break;
281 : case SHEETTYPE_CHARTSHEET:
282 0 : xFragment.set( new ChartsheetFragment( *xSheetGlob, aFragmentPath ) );
283 0 : break;
284 : default:
285 : OSL_ENSURE( false, "WorkbookFragment::finalizeImport - unexpected sheet type" );
286 : }
287 :
288 : // insert the fragment into the map
289 43 : if( xFragment.is() )
290 : {
291 43 : aSheetFragments.push_back( SheetFragmentHandler( xSheetGlob, xFragment.get() ) );
292 43 : maHelpers.push_back(xFragment.get());
293 43 : }
294 43 : }
295 43 : }
296 43 : }
297 : }
298 : }
299 :
300 : // create all defined names and database ranges
301 21 : getDefinedNames().finalizeImport();
302 21 : getTables().finalizeImport();
303 : // open the VBA project storage
304 21 : OUString aVbaFragmentPath = getFragmentPathFromFirstType( CREATE_MSOFFICE_RELATION_TYPE( "vbaProject" ) );
305 21 : if( !aVbaFragmentPath.isEmpty() )
306 : {
307 0 : Reference< XInputStream > xInStrm = getBaseFilter().openInputStream( aVbaFragmentPath );
308 0 : if( xInStrm.is() )
309 : {
310 0 : StorageRef xPrjStrg( new ::oox::ole::OleStorage( getBaseFilter().getComponentContext(), xInStrm, false ) );
311 0 : setVbaProjectStorage( xPrjStrg );
312 0 : getBaseFilter().getVbaProject().readVbaModules( *xPrjStrg );
313 0 : }
314 : }
315 :
316 : // load all worksheets
317 64 : for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt )
318 : {
319 : // import the sheet fragment
320 43 : importOoxFragment( aIt->second );
321 : }
322 :
323 64 : for( std::vector<WorksheetHelper*>::iterator aIt = maHelpers.begin(), aEnd = maHelpers.end(); aIt != aEnd; ++aIt )
324 : {
325 43 : (*aIt)->finalizeDrawingImport();
326 : }
327 :
328 64 : for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt )
329 : {
330 : // delete fragment object and WorkbookGlobals object, will free all allocated sheet buffers
331 43 : aIt->second.clear();
332 43 : aIt->first.reset();
333 : }
334 :
335 : // final conversions, e.g. calculation settings and view settings
336 21 : finalizeWorkbookImport();
337 :
338 : // Recalculate formula cells.
339 21 : ScDocument& rDoc = getScDocument();
340 21 : ScDocShell* pDocSh = static_cast<ScDocShell*>(rDoc.GetDocumentShell());
341 42 : Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
342 : ScRecalcOptions nRecalcMode =
343 21 : static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::get(xContext));
344 21 : bool bHardRecalc = false;
345 21 : if (nRecalcMode == RECALC_ASK)
346 : {
347 0 : if (rDoc.IsUserInteractionEnabled())
348 : {
349 : // Ask the user if full re-calculation is desired.
350 : QueryBox aBox(
351 : pDocSh->GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
352 0 : ScGlobal::GetRscString(STR_QUERY_FORMULA_RECALC_ONLOAD_XLS));
353 0 : aBox.SetCheckBoxText(ScGlobal::GetRscString(STR_ALWAYS_PERFORM_SELECTED));
354 :
355 0 : sal_Int32 nRet = aBox.Execute();
356 0 : bHardRecalc = nRet == RET_YES;
357 :
358 0 : if (aBox.GetCheckBoxState())
359 : {
360 : // Always perform selected action in the future.
361 0 : boost::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() );
362 0 : officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::set(sal_Int32(0), batch);
363 0 : ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions();
364 0 : aOpt.SetOOXMLRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
365 0 : SC_MOD()->SetFormulaOptions(aOpt);
366 :
367 0 : batch->commit();
368 0 : }
369 : }
370 : }
371 21 : else if (nRecalcMode == RECALC_ALWAYS)
372 0 : bHardRecalc = true;
373 :
374 21 : if (bHardRecalc)
375 0 : pDocSh->DoHardRecalc(false);
376 : else
377 63 : rDoc.CalcFormulaTree(false, true, false);
378 21 : }
379 :
380 : // private --------------------------------------------------------------------
381 :
382 0 : void WorkbookFragment::importExternalReference( const AttributeList& rAttribs )
383 : {
384 0 : if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() )
385 0 : importExternalLinkFragment( *pExtLink );
386 0 : }
387 :
388 11 : void WorkbookFragment::importDefinedName( const AttributeList& rAttribs )
389 : {
390 11 : mxCurrName = getDefinedNames().importDefinedName( rAttribs );
391 11 : }
392 :
393 0 : void WorkbookFragment::importPivotCache( const AttributeList& rAttribs )
394 : {
395 0 : sal_Int32 nCacheId = rAttribs.getInteger( XML_cacheId, -1 );
396 0 : OUString aRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
397 0 : importPivotCacheDefFragment( aRelId, nCacheId );
398 0 : }
399 :
400 0 : void WorkbookFragment::importExternalRef( SequenceInputStream& rStrm )
401 : {
402 0 : if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() )
403 0 : importExternalLinkFragment( *pExtLink );
404 0 : }
405 :
406 0 : void WorkbookFragment::importPivotCache( SequenceInputStream& rStrm )
407 : {
408 0 : sal_Int32 nCacheId = rStrm.readInt32();
409 0 : OUString aRelId = BiffHelper::readString( rStrm );
410 0 : importPivotCacheDefFragment( aRelId, nCacheId );
411 0 : }
412 :
413 0 : void WorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink )
414 : {
415 0 : OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() );
416 0 : if( !aFragmentPath.isEmpty() )
417 0 : importOoxFragment( new ExternalLinkFragment( *this, aFragmentPath, rExtLink ) );
418 0 : }
419 :
420 0 : void WorkbookFragment::importPivotCacheDefFragment( const OUString& rRelId, sal_Int32 nCacheId )
421 : {
422 : // pivot caches will be imported on demand, here we just store the fragment path in the buffer
423 0 : getPivotCaches().registerPivotCacheFragment( nCacheId, getFragmentPathFromRelId( rRelId ) );
424 0 : }
425 :
426 : } // namespace xls
427 15 : } // namespace oox
428 :
429 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|