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