diff options
Diffstat (limited to 'sc/source/filter/oox/workbookfragment.cxx')
-rw-r--r-- | sc/source/filter/oox/workbookfragment.cxx | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx new file mode 100644 index 000000000..4a99b4230 --- /dev/null +++ b/sc/source/filter/oox/workbookfragment.cxx @@ -0,0 +1,641 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <workbookfragment.hxx> + +#include <oox/core/filterbase.hxx> +#include <oox/core/xmlfilterbase.hxx> +#include <oox/drawingml/themefragmenthandler.hxx> +#include <oox/helper/attributelist.hxx> +#include <oox/helper/binaryinputstream.hxx> +#include <oox/helper/progressbar.hxx> +#include <oox/ole/olestorage.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/tokens.hxx> + +#include <chartsheetfragment.hxx> +#include <connectionsfragment.hxx> +#include <externallinkbuffer.hxx> +#include <externallinkfragment.hxx> +#include <formulabuffer.hxx> +#include <pivotcachebuffer.hxx> +#include <sharedstringsfragment.hxx> +#include <revisionfragment.hxx> +#include <stylesfragment.hxx> +#include <tablebuffer.hxx> +#include <themebuffer.hxx> +#include <viewsettings.hxx> +#include <workbooksettings.hxx> +#include <worksheetbuffer.hxx> +#include <worksheethelper.hxx> +#include <worksheetfragment.hxx> +#include <extlstcontext.hxx> +#include <documentimport.hxx> +#include <biffhelper.hxx> + +#include <document.hxx> +#include <drwlayer.hxx> +#include <docsh.hxx> +#include <calcconfig.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <scmod.hxx> +#include <formulaopt.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/timer.hxx> +#include <vcl/weld.hxx> + +#include <oox/core/fastparser.hxx> +#include <comphelper/threadpool.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> + +#include <memory> + +#include <oox/ole/vbaproject.hxx> + +#include <comphelper/processfactory.hxx> +#include <officecfg/Office/Calc.hxx> + +namespace oox::xls { + +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::uno; +using namespace ::oox::core; + +using ::oox::drawingml::ThemeFragmentHandler; + +namespace { + +const double PROGRESS_LENGTH_GLOBALS = 0.1; /// 10% of progress bar for globals import. + +} // namespace + +WorkbookFragment::WorkbookFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) : + WorkbookFragmentBase( rHelper, rFragmentPath ) +{ +} + +ContextHandlerRef WorkbookFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) +{ + switch( getCurrentElement() ) + { + case XML_ROOT_CONTEXT: + if( nElement == XLS_TOKEN( workbook ) ) return this; + break; + + case XLS_TOKEN( workbook ): + switch( nElement ) + { + case XLS_TOKEN( sheets ): + case XLS_TOKEN( bookViews ): + case XLS_TOKEN( externalReferences ): + case XLS_TOKEN( definedNames ): + case XLS_TOKEN( pivotCaches ): return this; + + case XLS_TOKEN( fileSharing ): getWorkbookSettings().importFileSharing( rAttribs ); break; + case XLS_TOKEN( workbookPr ): getWorkbookSettings().importWorkbookPr( rAttribs ); break; + case XLS_TOKEN( calcPr ): getWorkbookSettings().importCalcPr( rAttribs ); break; + case XLS_TOKEN( oleSize ): getViewSettings().importOleSize( rAttribs ); break; + + case XLS_TOKEN( extLst ): return new ExtLstGlobalWorkbookContext( *this ); + } + break; + + case XLS_TOKEN( sheets ): + if( nElement == XLS_TOKEN( sheet ) ) getWorksheets().importSheet( rAttribs ); + break; + case XLS_TOKEN( bookViews ): + if( nElement == XLS_TOKEN( workbookView ) ) getViewSettings().importWorkbookView( rAttribs ); + break; + case XLS_TOKEN( externalReferences ): + if( nElement == XLS_TOKEN( externalReference ) ) importExternalReference( rAttribs ); + break; + case XLS_TOKEN( definedNames ): + if( nElement == XLS_TOKEN( definedName ) ) { importDefinedName( rAttribs ); return this; } // collect formula + break; + case XLS_TOKEN( pivotCaches ): + if( nElement == XLS_TOKEN( pivotCache ) ) importPivotCache( rAttribs ); + break; + } + return nullptr; +} + +void WorkbookFragment::onCharacters( const OUString& rChars ) +{ + if( isCurrentElement( XLS_TOKEN( definedName ) ) && mxCurrName ) + mxCurrName->setFormula( rChars ); +} + +ContextHandlerRef WorkbookFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) +{ + switch( getCurrentElement() ) + { + case XML_ROOT_CONTEXT: + if( nRecId == BIFF12_ID_WORKBOOK ) return this; + break; + + case BIFF12_ID_WORKBOOK: + switch( nRecId ) + { + case BIFF12_ID_SHEETS: + case BIFF12_ID_BOOKVIEWS: + case BIFF12_ID_EXTERNALREFS: + case BIFF12_ID_PIVOTCACHES: return this; + + case BIFF12_ID_FILESHARING: getWorkbookSettings().importFileSharing( rStrm ); break; + case BIFF12_ID_WORKBOOKPR: getWorkbookSettings().importWorkbookPr( rStrm ); break; + case BIFF12_ID_CALCPR: getWorkbookSettings().importCalcPr( rStrm ); break; + case BIFF12_ID_OLESIZE: getViewSettings().importOleSize( rStrm ); break; + case BIFF12_ID_DEFINEDNAME: getDefinedNames().importDefinedName( rStrm ); break; + } + break; + + case BIFF12_ID_SHEETS: + if( nRecId == BIFF12_ID_SHEET ) getWorksheets().importSheet( rStrm ); + break; + case BIFF12_ID_BOOKVIEWS: + if( nRecId == BIFF12_ID_WORKBOOKVIEW ) getViewSettings().importWorkbookView( rStrm ); + break; + + case BIFF12_ID_EXTERNALREFS: + switch( nRecId ) + { + case BIFF12_ID_EXTERNALREF: importExternalRef( rStrm ); break; + case BIFF12_ID_EXTERNALSELF: getExternalLinks().importExternalSelf( rStrm ); break; + case BIFF12_ID_EXTERNALSAME: getExternalLinks().importExternalSame( rStrm ); break; + case BIFF12_ID_EXTERNALADDIN: getExternalLinks().importExternalAddin( rStrm ); break; + case BIFF12_ID_EXTERNALSHEETS: getExternalLinks().importExternalSheets( rStrm ); break; + } + break; + + case BIFF12_ID_PIVOTCACHES: + if( nRecId == BIFF12_ID_PIVOTCACHE ) importPivotCache( rStrm ); + } + return nullptr; +} + +const RecordInfo* WorkbookFragment::getRecordInfos() const +{ + static const RecordInfo spRecInfos[] = + { + { BIFF12_ID_BOOKVIEWS, BIFF12_ID_BOOKVIEWS + 1 }, + { BIFF12_ID_EXTERNALREFS, BIFF12_ID_EXTERNALREFS + 1 }, + { BIFF12_ID_FUNCTIONGROUPS, BIFF12_ID_FUNCTIONGROUPS + 2 }, + { BIFF12_ID_PIVOTCACHE, BIFF12_ID_PIVOTCACHE + 1 }, + { BIFF12_ID_PIVOTCACHES, BIFF12_ID_PIVOTCACHES + 1 }, + { BIFF12_ID_SHEETS, BIFF12_ID_SHEETS + 1 }, + { BIFF12_ID_WORKBOOK, BIFF12_ID_WORKBOOK + 1 }, + { -1, -1 } + }; + return spRecInfos; +} + +namespace { + +typedef std::pair<WorksheetGlobalsRef, FragmentHandlerRef> SheetFragmentHandler; +typedef std::vector<SheetFragmentHandler> SheetFragmentVector; + +class WorkerThread : public comphelper::ThreadTask +{ + sal_Int32 &mrSheetsLeft; + WorkbookFragment& mrWorkbookHandler; + rtl::Reference<FragmentHandler> mxHandler; + +public: + WorkerThread( const std::shared_ptr<comphelper::ThreadTaskTag> & pTag, + WorkbookFragment& rWorkbookHandler, + const rtl::Reference<FragmentHandler>& xHandler, + sal_Int32 &rSheetsLeft ) : + comphelper::ThreadTask( pTag ), + mrSheetsLeft( rSheetsLeft ), + mrWorkbookHandler( rWorkbookHandler ), + mxHandler( xHandler ) + { + } + + virtual void doWork() override + { + // We hold the solar mutex in all threads except for + // the small safe section of the inner loop in + // sheetdatacontext.cxx + SAL_INFO( "sc.filter", "start wait on solar" ); + SolarMutexGuard aGuard; + SAL_INFO( "sc.filter", "got solar" ); + + std::unique_ptr<oox::core::FastParser> xParser( + oox::core::XmlFilterBase::createParser() ); + + SAL_INFO( "sc.filter", "start import" ); + mrWorkbookHandler.importOoxFragment( mxHandler, *xParser ); + SAL_INFO( "sc.filter", "end import, release solar" ); + mrSheetsLeft--; + assert( mrSheetsLeft >= 0 ); + if( mrSheetsLeft == 0 ) + Application::EndYield(); + } +}; + +class ProgressBarTimer : private Timer +{ + // FIXME: really we should unify all sheet loading + // progress reporting into something pleasant. + class ProgressWrapper : public ISegmentProgressBar + { + double mfPosition; + ISegmentProgressBarRef mxWrapped; + public: + explicit ProgressWrapper(const ISegmentProgressBarRef &xRef) + : mfPosition(0.0) + , mxWrapped(xRef) + { + } + + // IProgressBar + virtual double getPosition() const override { return mfPosition; } + virtual void setPosition( double fPosition ) override { mfPosition = fPosition; } + // ISegmentProgressBar + virtual double getFreeLength() const override { return 0.0; } + virtual ISegmentProgressBarRef createSegment( double /* fLength */ ) override + { + return ISegmentProgressBarRef(); + } + void UpdateBar() + { + mxWrapped->setPosition( mfPosition ); + } + }; + std::vector< ISegmentProgressBarRef > aSegments; +public: + ProgressBarTimer() : Timer("sc ProgressBarTimer") + { + SetTimeout( 500 ); + } + virtual ~ProgressBarTimer() override + { + aSegments.clear(); + } + const ISegmentProgressBarRef& wrapProgress( const ISegmentProgressBarRef &xProgress ) + { + aSegments.push_back( std::make_shared<ProgressWrapper>( xProgress ) ); + return aSegments.back(); + } + virtual void Invoke() override + { + for(std::shared_ptr<ISegmentProgressBar> & pSegment : aSegments) + static_cast< ProgressWrapper *>( pSegment.get() )->UpdateBar(); + } +}; + +void importSheetFragments( WorkbookFragment& rWorkbookHandler, SheetFragmentVector& rSheets ) +{ + rWorkbookHandler.getDocImport().initForSheets(); + + // test sequential read in this mode + comphelper::ThreadPool &rSharedPool = comphelper::ThreadPool::getSharedOptimalPool(); + std::shared_ptr<comphelper::ThreadTaskTag> pTag = comphelper::ThreadPool::createThreadTaskTag(); + + sal_Int32 nSheetsLeft = 0; + ProgressBarTimer aProgressUpdater; + for( auto& [rxSheetGlob, rxFragment] : rSheets ) + { + // getting at the WorksheetGlobals is rather unpleasant + IWorksheetProgress *pProgress = WorksheetHelper::getWorksheetInterface( rxSheetGlob ); + pProgress->setCustomRowProgress( + aProgressUpdater.wrapProgress( + pProgress->getRowProgress() ) ); + rSharedPool.pushTask( std::make_unique<WorkerThread>( pTag, rWorkbookHandler, rxFragment, + /* ref */ nSheetsLeft ) ); + nSheetsLeft++; + } + + // coverity[loop_top] - this isn't an infinite loop where nSheetsLeft gets decremented by the above threads + while( nSheetsLeft > 0 && !Application::IsQuit()) + { + // This is a much more controlled re-enterancy hazard than + // allowing a yield deeper inside the filter code for progress + // bar updating. + Application::Yield(); + } + rSharedPool.waitUntilDone(pTag); + + // threads joined in ThreadPool destructor +} + +} + +void WorkbookFragment::finalizeImport() +{ + ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS ); + + // read the theme substream + OUString aThemeFragmentPath = getFragmentPathFromFirstTypeFromOfficeDoc( u"theme" ); + if( !aThemeFragmentPath.isEmpty() ) + importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme() ) ); + xGlobalSegment->setPosition( 0.25 ); + + // read the styles substream (requires finalized theme buffer) + OUString aStylesFragmentPath = getFragmentPathFromFirstTypeFromOfficeDoc( u"styles" ); + if( !aStylesFragmentPath.isEmpty() ) + importOoxFragment( new StylesFragment( *this, aStylesFragmentPath ) ); + xGlobalSegment->setPosition( 0.5 ); + + // read the shared string table substream (requires finalized styles buffer) + OUString aSstFragmentPath = getFragmentPathFromFirstTypeFromOfficeDoc( u"sharedStrings" ); + if( !aSstFragmentPath.isEmpty() ) + if (!importOoxFragment( new SharedStringsFragment( *this, aSstFragmentPath ) )) + importOoxFragment(new SharedStringsFragment(*this, aSstFragmentPath.replaceFirst("sharedStrings","SharedStrings"))); + xGlobalSegment->setPosition( 0.75 ); + + // read the connections substream + OUString aConnFragmentPath = getFragmentPathFromFirstTypeFromOfficeDoc( u"connections" ); + if( !aConnFragmentPath.isEmpty() ) + importOoxFragment( new ConnectionsFragment( *this, aConnFragmentPath ) ); + xGlobalSegment->setPosition( 1.0 ); + + /* Create fragments for all sheets, before importing them. Needed to do + some preprocessing in the fragment constructors, e.g. loading the table + fragments for all sheets that are needed before the cell formulas are + loaded. Additionally, the instances of the WorkbookGlobals structures + have to be stored for every sheet. */ + SheetFragmentVector aSheetFragments; + std::vector<WorksheetHelper*> aHelpers; + WorksheetBuffer& rWorksheets = getWorksheets(); + sal_Int32 nWorksheetCount = rWorksheets.getWorksheetCount(); + for( sal_Int32 nWorksheet = 0; nWorksheet < nWorksheetCount; ++nWorksheet ) + { + sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet ); + const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getWorksheetRelId( nWorksheet ) ); + if( (nCalcSheet >= 0) && pRelation ) + { + // get fragment path of the sheet + OUString aFragmentPath = getFragmentPathFromRelation( *pRelation ); + OSL_ENSURE( !aFragmentPath.isEmpty(), "WorkbookFragment::finalizeImport - cannot access sheet fragment" ); + if( !aFragmentPath.isEmpty() ) + { + // leave space for formula processing ( calculate the segments as + // if there is an extra sheet ) + double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - ( nWorksheet - 1) ); + ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength ); + + // get the sheet type according to the relations type + WorksheetType eSheetType = WorksheetType::Empty; + if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "worksheet" ) || + pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "worksheet" )) + eSheetType = WorksheetType::Work; + else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "chartsheet" ) || + pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "chartsheet" )) + eSheetType = WorksheetType::Chart; + else if( (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlMacrosheet" )) || + (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlIntlMacrosheet" )) ) + eSheetType = WorksheetType::Macro; + else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "dialogsheet" ) || + pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE_STRICT(" dialogsheet" )) + eSheetType = WorksheetType::Dialog; + OSL_ENSURE( eSheetType != WorksheetType::Empty, "WorkbookFragment::finalizeImport - unknown sheet type" ); + if( eSheetType != WorksheetType::Empty ) + { + // create the WorksheetGlobals object + WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetSegment, eSheetType, nCalcSheet ); + OSL_ENSURE( xSheetGlob, "WorkbookFragment::finalizeImport - missing sheet in document" ); + if( xSheetGlob ) + { + // create the sheet fragment handler + ::rtl::Reference< WorksheetFragmentBase > xFragment; + switch( eSheetType ) + { + case WorksheetType::Work: + case WorksheetType::Macro: + case WorksheetType::Dialog: + xFragment.set( new WorksheetFragment( *xSheetGlob, aFragmentPath ) ); + break; + case WorksheetType::Chart: + xFragment.set( new ChartsheetFragment( *xSheetGlob, aFragmentPath ) ); + break; + // coverity[dead_error_begin] - following conditions exist to avoid compiler warning + case WorksheetType::Empty: + break; + } + + // insert the fragment into the map + if( xFragment.is() ) + { + aSheetFragments.emplace_back( xSheetGlob, xFragment.get() ); + aHelpers.push_back(xFragment.get()); + } + } + } + } + } + } + + // setup structure sizes for the number of sheets + getFormulaBuffer().SetSheetCount( nWorksheetCount ); + + // create all database ranges and defined names, in that order + getTables().finalizeImport(); + getTables().applyTableColumns(); + getDefinedNames().finalizeImport(); + // open the VBA project storage + OUString aVbaFragmentPath = getFragmentPathFromFirstType( CREATE_MSOFFICE_RELATION_TYPE( "vbaProject" ) ); + if( !aVbaFragmentPath.isEmpty() ) + { + Reference< XInputStream > xInStrm = getBaseFilter().openInputStream( aVbaFragmentPath ); + if( xInStrm.is() ) + { + StorageRef xPrjStrg = std::make_shared<::oox::ole::OleStorage>( getBaseFilter().getComponentContext(), xInStrm, false ); + setVbaProjectStorage( xPrjStrg ); + getBaseFilter().getVbaProject().readVbaModules( *xPrjStrg ); + } + } + + // lock the model to prevent broadcasting, speeds up load a lot + getScDocument().InitDrawLayer(); + auto pModel = getScDocument().GetDrawLayer(); + bool bWasLocked = pModel->isLocked(); + pModel->setLock(true); + + // load all worksheets + importSheetFragments(*this, aSheetFragments); + + sal_Int16 nActiveSheet = getViewSettings().getActiveCalcSheet(); + getWorksheets().finalizeImport( nActiveSheet ); + + // final conversions, e.g. calculation settings and view settings + finalizeWorkbookImport(); + + //stop preventing establishment of listeners as is done in + //ScDocShell::AfterXMLLoading() for ods + getScDocument().SetInsertingFromOtherDoc(false); + + for( WorksheetHelper* pHelper : aHelpers ) + { + pHelper->finalizeDrawingImport(); + } + + for( auto& [rxSheetGlob, rxFragment] : aSheetFragments ) + { + // delete fragment object and WorkbookGlobals object, will free all allocated sheet buffers + rxFragment.clear(); + rxSheetGlob.reset(); + } + + getDocImport().finalize(); + + recalcFormulaCells(); + + OUString aRevHeadersPath = getFragmentPathFromFirstType(CREATE_OFFICEDOC_RELATION_TYPE("revisionHeaders")); + if (!aRevHeadersPath.isEmpty()) + { + std::unique_ptr<oox::core::FastParser> xParser(oox::core::XmlFilterBase::createParser()); + rtl::Reference<oox::core::FragmentHandler> xFragment(new RevisionHeadersFragment(*this, aRevHeadersPath)); + importOoxFragment(xFragment, *xParser); + } + + // attach macros to registered objects now that all objects have been created. + getBaseFilter().getVbaProject().attachMacros(); + + pModel->setLock(bWasLocked); +} + +namespace { + +ScDocShell& getDocShell(const ScDocument& rDoc) +{ + return static_cast<ScDocShell&>(*rDoc.GetDocumentShell()); +} + +class MessageWithCheck : public weld::MessageDialogController +{ +private: + std::unique_ptr<weld::CheckButton> m_xWarningOnBox; +public: + MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OString& rDialogId) + : MessageDialogController(pParent, rUIFile, rDialogId, "ask") + , m_xWarningOnBox(m_xBuilder->weld_check_button("ask")) + { + } + bool get_active() const { return m_xWarningOnBox->get_active(); } + void hide_ask() const { m_xWarningOnBox->set_visible(false); }; +}; + +} + +void WorkbookFragment::recalcFormulaCells() +{ + // Recalculate formula cells. + ScDocument& rDoc = getScDocument(); + ScDocShell& rDocSh = getDocShell(rDoc); + ScRecalcOptions nRecalcMode = + static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::get()); + bool bHardRecalc = false; + if (nRecalcMode == RECALC_ASK) + { + if (rDoc.IsUserInteractionEnabled()) + { + // Ask the user if full re-calculation is desired. + MessageWithCheck aQueryBox(ScDocShell::GetActiveDialogParent(), "modules/scalc/ui/recalcquerydialog.ui", "RecalcQueryDialog"); + aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_XLS)); + aQueryBox.set_default_response(RET_YES); + + if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() ) + aQueryBox.hide_ask(); + + bHardRecalc = aQueryBox.run() == RET_YES; + + if (aQueryBox.get_active()) + { + // Always perform selected action in the future. + std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::set(sal_Int32(0), batch); + ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions(); + aOpt.SetOOXMLRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER); + /* XXX is this really supposed to set the ScModule options? + * Not the ScDocShell options? */ + SC_MOD()->SetFormulaOptions(aOpt); + + batch->commit(); + } + } + } + else if (nRecalcMode == RECALC_ALWAYS) + bHardRecalc = true; + + if (bHardRecalc) + rDocSh.DoHardRecalc(); + else + { + getDocImport().broadcastRecalcAfterImport(); + // Full ScDocument::CalcFormulaTree() of all dirty cells is not + // necessary here, the View will recalculate them in the visible area, + // or any other method accessing formula cell results. + } +} + +// private -------------------------------------------------------------------- + +void WorkbookFragment::importExternalReference( const AttributeList& rAttribs ) +{ + if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() ) + importExternalLinkFragment( *pExtLink ); +} + +void WorkbookFragment::importDefinedName( const AttributeList& rAttribs ) +{ + mxCurrName = getDefinedNames().importDefinedName( rAttribs ); +} + +void WorkbookFragment::importPivotCache( const AttributeList& rAttribs ) +{ + sal_Int32 nCacheId = rAttribs.getInteger( XML_cacheId, -1 ); + OUString aRelId = rAttribs.getString( R_TOKEN( id ), OUString() ); + importPivotCacheDefFragment( aRelId, nCacheId ); +} + +void WorkbookFragment::importExternalRef( SequenceInputStream& rStrm ) +{ + if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() ) + importExternalLinkFragment( *pExtLink ); +} + +void WorkbookFragment::importPivotCache( SequenceInputStream& rStrm ) +{ + sal_Int32 nCacheId = rStrm.readInt32(); + OUString aRelId = BiffHelper::readString( rStrm ); + importPivotCacheDefFragment( aRelId, nCacheId ); +} + +void WorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink ) +{ + OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() ); + if( !aFragmentPath.isEmpty() ) + importOoxFragment( new ExternalLinkFragment( *this, aFragmentPath, rExtLink ) ); +} + +void WorkbookFragment::importPivotCacheDefFragment( const OUString& rRelId, sal_Int32 nCacheId ) +{ + // pivot caches will be imported on demand, here we just store the fragment path in the buffer + getPivotCaches().registerPivotCacheFragment( nCacheId, getFragmentPathFromRelId( rRelId ) ); +} + +} // namespace oox + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |