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 :
55 : namespace oox {
56 : namespace xls {
57 :
58 : // ============================================================================
59 :
60 : using namespace ::com::sun::star::io;
61 : using namespace ::com::sun::star::table;
62 : using namespace ::com::sun::star::uno;
63 : using namespace ::com::sun::star::sheet;
64 : using namespace ::oox::core;
65 :
66 : using ::oox::drawingml::ThemeFragmentHandler;
67 : using ::rtl::OUString;
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 11 : WorkbookFragment::WorkbookFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
80 11 : WorkbookFragmentBase( rHelper, rFragmentPath )
81 : {
82 11 : }
83 :
84 124 : ContextHandlerRef WorkbookFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
85 : {
86 124 : switch( getCurrentElement() )
87 : {
88 : case XML_ROOT_CONTEXT:
89 11 : if( nElement == XLS_TOKEN( workbook ) ) return this;
90 0 : break;
91 :
92 : case XLS_TOKEN( workbook ):
93 66 : switch( nElement )
94 : {
95 : case XLS_TOKEN( sheets ):
96 : case XLS_TOKEN( bookViews ):
97 : case XLS_TOKEN( externalReferences ):
98 : case XLS_TOKEN( definedNames ):
99 24 : case XLS_TOKEN( pivotCaches ): return this;
100 :
101 0 : case XLS_TOKEN( fileSharing ): getWorkbookSettings().importFileSharing( rAttribs ); break;
102 11 : case XLS_TOKEN( workbookPr ): getWorkbookSettings().importWorkbookPr( rAttribs ); break;
103 11 : case XLS_TOKEN( calcPr ): getWorkbookSettings().importCalcPr( rAttribs ); break;
104 0 : case XLS_TOKEN( oleSize ): getViewSettings().importOleSize( rAttribs ); break;
105 : }
106 42 : break;
107 :
108 : case XLS_TOKEN( sheets ):
109 25 : if( nElement == XLS_TOKEN( sheet ) ) getWorksheets().importSheet( rAttribs );
110 25 : break;
111 : case XLS_TOKEN( bookViews ):
112 11 : if( nElement == XLS_TOKEN( workbookView ) ) getViewSettings().importWorkbookView( rAttribs );
113 11 : 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 78 : 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 11 : void WorkbookFragment::finalizeImport()
198 : {
199 11 : ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
200 :
201 : // read the theme substream
202 11 : OUString aThemeFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "theme" ) );
203 11 : if( !aThemeFragmentPath.isEmpty() )
204 4 : importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme() ) );
205 11 : xGlobalSegment->setPosition( 0.25 );
206 :
207 : // read the styles substream (requires finalized theme buffer)
208 11 : OUString aStylesFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "styles" ) );
209 11 : if( !aStylesFragmentPath.isEmpty() )
210 11 : importOoxFragment( new StylesFragment( *this, aStylesFragmentPath ) );
211 11 : xGlobalSegment->setPosition( 0.5 );
212 :
213 : // read the shared string table substream (requires finalized styles buffer)
214 11 : OUString aSstFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "sharedStrings" ) );
215 11 : if( !aSstFragmentPath.isEmpty() )
216 9 : importOoxFragment( new SharedStringsFragment( *this, aSstFragmentPath ) );
217 11 : xGlobalSegment->setPosition( 0.75 );
218 :
219 : // read the connections substream
220 11 : OUString aConnFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "connections" ) );
221 11 : if( !aConnFragmentPath.isEmpty() )
222 0 : importOoxFragment( new ConnectionsFragment( *this, aConnFragmentPath ) );
223 11 : 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 11 : SheetFragmentVector aSheetFragments;
234 11 : WorksheetBuffer& rWorksheets = getWorksheets();
235 11 : sal_Int32 nWorksheetCount = rWorksheets.getWorksheetCount();
236 36 : for( sal_Int32 nWorksheet = 0; nWorksheet < nWorksheetCount; ++nWorksheet )
237 : {
238 25 : sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet );
239 25 : const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getWorksheetRelId( nWorksheet ) );
240 25 : if( (nCalcSheet >= 0) && pRelation )
241 : {
242 : // get fragment path of the sheet
243 25 : OUString aFragmentPath = getFragmentPathFromRelation( *pRelation );
244 : OSL_ENSURE( !aFragmentPath.isEmpty(), "WorkbookFragment::finalizeImport - cannot access sheet fragment" );
245 25 : if( !aFragmentPath.isEmpty() )
246 : {
247 : // leave space for formula processing ( calcuate the segments as
248 : // if there is an extra sheet )
249 25 : double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - ( nWorksheet - 1) );
250 25 : ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength );
251 :
252 : // get the sheet type according to the relations type
253 25 : WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET;
254 25 : if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "worksheet" ) )
255 25 : eSheetType = SHEETTYPE_WORKSHEET;
256 0 : else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "chartsheet" ) )
257 0 : eSheetType = SHEETTYPE_CHARTSHEET;
258 0 : else if( (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlMacrosheet" )) ||
259 0 : (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlIntlMacrosheet" )) )
260 0 : eSheetType = SHEETTYPE_MACROSHEET;
261 0 : else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "dialogsheet" ) )
262 0 : eSheetType = SHEETTYPE_DIALOGSHEET;
263 : OSL_ENSURE( eSheetType != SHEETTYPE_EMPTYSHEET, "WorkbookFragment::finalizeImport - unknown sheet type" );
264 25 : if( eSheetType != SHEETTYPE_EMPTYSHEET )
265 : {
266 : // create the WorksheetGlobals object
267 25 : WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetSegment, eSheetType, nCalcSheet );
268 : OSL_ENSURE( xSheetGlob.get(), "WorkbookFragment::finalizeImport - missing sheet in document" );
269 25 : if( xSheetGlob.get() )
270 : {
271 : // create the sheet fragment handler
272 25 : ::rtl::Reference< WorksheetFragmentBase > xFragment;
273 25 : switch( eSheetType )
274 : {
275 : case SHEETTYPE_WORKSHEET:
276 : case SHEETTYPE_MACROSHEET:
277 : case SHEETTYPE_DIALOGSHEET:
278 25 : xFragment.set( new WorksheetFragment( *xSheetGlob, aFragmentPath ) );
279 25 : break;
280 : case SHEETTYPE_CHARTSHEET:
281 0 : xFragment.set( new ChartsheetFragment( *xSheetGlob, aFragmentPath ) );
282 0 : break;
283 : default:
284 : OSL_ENSURE( false, "WorkbookFragment::finalizeImport - unexpected sheet type" );
285 : }
286 :
287 : // insert the fragment into the map
288 25 : if( xFragment.is() )
289 25 : aSheetFragments.push_back( SheetFragmentHandler( xSheetGlob, xFragment.get() ) );
290 25 : }
291 25 : }
292 25 : }
293 : }
294 : }
295 :
296 : // create all defined names and database ranges
297 11 : getDefinedNames().finalizeImport();
298 11 : getTables().finalizeImport();
299 : // load all worksheets
300 36 : for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt )
301 : {
302 : // import the sheet fragment
303 25 : importOoxFragment( aIt->second );
304 : // delete fragment object and WorkbookGlobals object, will free all allocated sheet buffers
305 25 : aIt->second.clear();
306 25 : aIt->first.reset();
307 : }
308 :
309 : // open the VBA project storage
310 11 : OUString aVbaFragmentPath = getFragmentPathFromFirstType( CREATE_MSOFFICE_RELATION_TYPE( "vbaProject" ) );
311 11 : if( !aVbaFragmentPath.isEmpty() )
312 : {
313 0 : Reference< XInputStream > xInStrm = getBaseFilter().openInputStream( aVbaFragmentPath );
314 0 : if( xInStrm.is() )
315 0 : setVbaProjectStorage( StorageRef( new ::oox::ole::OleStorage( getBaseFilter().getComponentContext(), xInStrm, false ) ) );
316 : }
317 :
318 : // final conversions, e.g. calculation settings and view settings
319 11 : finalizeWorkbookImport();
320 :
321 : // Recalculate formula cells.
322 11 : ScDocument& rDoc = getScDocument();
323 11 : ScDocShell* pDocSh = static_cast<ScDocShell*>(rDoc.GetDocumentShell());
324 11 : Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
325 : ScRecalcOptions nRecalcMode =
326 11 : static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::get(xContext));
327 11 : bool bHardRecalc = false;
328 11 : if (nRecalcMode == RECALC_ASK)
329 : {
330 0 : if (rDoc.IsUserInteractionEnabled())
331 : {
332 : // Ask the user if full re-calculation is desired.
333 : QueryBox aBox(
334 : pDocSh->GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
335 0 : ScGlobal::GetRscString(STR_QUERY_FORMULA_RECALC_ONLOAD_XLS));
336 0 : aBox.SetCheckBoxText(ScGlobal::GetRscString(STR_ALWAYS_PERFORM_SELECTED));
337 :
338 0 : sal_Int32 nRet = aBox.Execute();
339 0 : bHardRecalc = nRet == RET_YES;
340 :
341 0 : if (aBox.GetCheckBoxState())
342 : {
343 : // Always perform selected action in the future.
344 0 : boost::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() );
345 0 : officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::set(sal_Int32(0), batch);
346 0 : ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions();
347 0 : aOpt.SetOOXMLRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
348 0 : SC_MOD()->SetFormulaOptions(aOpt);
349 :
350 0 : batch->commit();
351 0 : }
352 : }
353 : }
354 11 : else if (nRecalcMode == RECALC_ALWAYS)
355 0 : bHardRecalc = true;
356 :
357 11 : if (bHardRecalc)
358 0 : pDocSh->DoHardRecalc(false);
359 : else
360 11 : rDoc.CalcFormulaTree(false, true, false);
361 11 : }
362 :
363 : // private --------------------------------------------------------------------
364 :
365 0 : void WorkbookFragment::importExternalReference( const AttributeList& rAttribs )
366 : {
367 0 : if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() )
368 0 : importExternalLinkFragment( *pExtLink );
369 0 : }
370 :
371 11 : void WorkbookFragment::importDefinedName( const AttributeList& rAttribs )
372 : {
373 11 : mxCurrName = getDefinedNames().importDefinedName( rAttribs );
374 11 : }
375 :
376 0 : void WorkbookFragment::importPivotCache( const AttributeList& rAttribs )
377 : {
378 0 : sal_Int32 nCacheId = rAttribs.getInteger( XML_cacheId, -1 );
379 0 : OUString aRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
380 0 : importPivotCacheDefFragment( aRelId, nCacheId );
381 0 : }
382 :
383 0 : void WorkbookFragment::importExternalRef( SequenceInputStream& rStrm )
384 : {
385 0 : if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() )
386 0 : importExternalLinkFragment( *pExtLink );
387 0 : }
388 :
389 0 : void WorkbookFragment::importPivotCache( SequenceInputStream& rStrm )
390 : {
391 0 : sal_Int32 nCacheId = rStrm.readInt32();
392 0 : OUString aRelId = BiffHelper::readString( rStrm );
393 0 : importPivotCacheDefFragment( aRelId, nCacheId );
394 0 : }
395 :
396 0 : void WorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink )
397 : {
398 0 : OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() );
399 0 : if( !aFragmentPath.isEmpty() )
400 0 : importOoxFragment( new ExternalLinkFragment( *this, aFragmentPath, rExtLink ) );
401 0 : }
402 :
403 0 : void WorkbookFragment::importPivotCacheDefFragment( const OUString& rRelId, sal_Int32 nCacheId )
404 : {
405 : // pivot caches will be imported on demand, here we just store the fragment path in the buffer
406 0 : getPivotCaches().registerPivotCacheFragment( nCacheId, getFragmentPathFromRelId( rRelId ) );
407 0 : }
408 :
409 : } // namespace xls
410 9 : } // namespace oox
411 :
412 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|