/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xmlimp.hxx" #include "xmlimpit.hxx" #include "xmltexti.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::text; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; using namespace ::com::sun::star::i18n; using namespace ::com::sun::star::drawing; using namespace ::com::sun::star::xforms; using namespace ::xmloff::token; using namespace ::std; namespace { class SwXMLBodyContext_Impl : public SvXMLImportContext { SwXMLImport& GetSwImport() { return static_cast(GetImport()); } public: SwXMLBodyContext_Impl( SwXMLImport& rImport ); virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; }; } SwXMLBodyContext_Impl::SwXMLBodyContext_Impl( SwXMLImport& rImport ) : SvXMLImportContext( rImport ) { // tdf#107211: if at this point we don't have a defined char style "Default" // or "Default Style", add a mapping for it as it is not written // into the file since it's not really a style but "no style" // (hence referencing it actually makes no sense except for hyperlinks // which default to something other than "Default") OUString const sDefault(SwResId(STR_POOLCHR_STANDARD)); uno::Reference const& xStyles( rImport.GetTextImport()->GetTextStyles()); if (!xStyles->hasByName("Default")) { // this old name was used before LO 4.0 rImport.AddStyleDisplayName(XmlStyleFamily::TEXT_TEXT, "Default", sDefault); } if (!xStyles->hasByName("Default_20_Style")) { // this new name contains a space which is converted to _20_ on export rImport.AddStyleDisplayName(XmlStyleFamily::TEXT_TEXT, "Default_20_Style", sDefault); } bool isEncoded(false); OUString const defaultEncoded( rImport.GetMM100UnitConverter().encodeStyleName(sDefault, &isEncoded)); if (isEncoded && defaultEncoded != "Default_20_Style" && !xStyles->hasByName(defaultEncoded)) { // new name may contain a space which is converted to _20_ on export rImport.AddStyleDisplayName(XmlStyleFamily::TEXT_TEXT, defaultEncoded, sDefault); } } css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLBodyContext_Impl::createFastChildContext( sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) { return GetSwImport().CreateBodyContentContext(); } namespace { // #i69629# // enhance class in order to be able to create subclasses // NB: virtually inherit so we can multiply inherit properly // in SwXMLOfficeDocContext_Impl class SwXMLDocContext_Impl : public virtual SvXMLImportContext { sal_Int32 mnElement; protected: // #i69629# SwXMLImport& GetSwImport() { return static_cast(GetImport()); } public: SwXMLDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement ); virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; }; } SwXMLDocContext_Impl::SwXMLDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement ) : SvXMLImportContext( rImport ), mnElement(nElement) { } uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SwXMLDocContext_Impl::createFastChildContext( sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) { switch (nElement) { case XML_ELEMENT(OFFICE, XML_SCRIPTS): return GetSwImport().CreateScriptContext(); case XML_ELEMENT(OFFICE, XML_SETTINGS): return new XMLDocumentSettingsContext( GetImport() ); case XML_ELEMENT(OFFICE, XML_STYLES): GetSwImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); return GetSwImport().CreateStylesContext( false ); case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): // don't use the autostyles from the styles-document for the progress if ( mnElement != 0 && (mnElement & TOKEN_MASK) != XML_DOCUMENT_STYLES ) GetSwImport().GetProgressBarHelper()->Increment ( PROGRESS_BAR_STEP ); return GetSwImport().CreateStylesContext( true ); case XML_ELEMENT(OFFICE, XML_MASTER_STYLES): return GetSwImport().CreateMasterStylesContext(); case XML_ELEMENT(OFFICE, XML_FONT_FACE_DECLS): return GetSwImport().CreateFontDeclsContext(); case XML_ELEMENT(OFFICE, XML_META): OSL_FAIL(" XML_ELEMENT(OFFICE, XML_META): should not have come here, maybe document is invalid?"); break; case XML_ELEMENT(OFFICE, XML_BODY): GetSwImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); return new SwXMLBodyContext_Impl( GetSwImport() ); case XML_ELEMENT(XFORMS, XML_MODEL): return createXFormsModelContext(GetImport()); default: XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement); } return nullptr; } namespace { // #i69629# - new subclass of class class SwXMLOfficeDocContext_Impl : public SwXMLDocContext_Impl, public SvXMLMetaDocumentContext { public: SwXMLOfficeDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement, const Reference< document::XDocumentProperties >& xDocProps); virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; }; } SwXMLOfficeDocContext_Impl::SwXMLOfficeDocContext_Impl( SwXMLImport& rImport, sal_Int32 nElement, const Reference< document::XDocumentProperties >& xDocProps) : SvXMLImportContext( rImport ), SwXMLDocContext_Impl( rImport, nElement ), SvXMLMetaDocumentContext( rImport, xDocProps ) { } uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SwXMLOfficeDocContext_Impl::createFastChildContext( sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) { // assign paragraph styles to list levels of outline style after all styles // are imported and finished. This is the case, when starts // in flat OpenDocument file format. { if( nElement == XML_ELEMENT( OFFICE, XML_BODY ) ) { GetImport().GetTextImport()->SetOutlineStyles( true ); } } // behave like meta base class iff we encounter office:meta if ( nElement == XML_ELEMENT( OFFICE, XML_META ) ) { return SvXMLMetaDocumentContext::createFastChildContext( nElement, xAttrList ); } else { return SwXMLDocContext_Impl::createFastChildContext( nElement, xAttrList ); } } namespace { // #i69629# - new subclass of class class SwXMLDocStylesContext_Impl : public SwXMLDocContext_Impl { public: SwXMLDocStylesContext_Impl( SwXMLImport& rImport, sal_Int32 nElement ); virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; }; } SwXMLDocStylesContext_Impl::SwXMLDocStylesContext_Impl( SwXMLImport& rImport, sal_Int32 nElement ) : SvXMLImportContext( rImport ), SwXMLDocContext_Impl( rImport, nElement ) { } void SwXMLDocStylesContext_Impl::endFastElement(sal_Int32 ) { // assign paragraph styles to list levels of outline style after all styles // are imported and finished. SwXMLImport& rSwImport = dynamic_cast( GetImport()); GetImport().GetTextImport()->SetOutlineStyles( bool(rSwImport.GetStyleFamilyMask() & SfxStyleFamily::Para)); } SvXMLImportContext *SwXMLImport::CreateFastContext( sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) { SvXMLImportContext *pContext = nullptr; switch (nElement) { case XML_ELEMENT( OFFICE, XML_DOCUMENT_META ): pContext = CreateMetaContext(nElement); break; case XML_ELEMENT( OFFICE, XML_DOCUMENT ): { uno::Reference const xDocProps( GetDocumentProperties()); // flat OpenDocument file format pContext = new SwXMLOfficeDocContext_Impl( *this, nElement, xDocProps ); } break; // #i69629# - own subclasses for and case XML_ELEMENT(OFFICE, XML_DOCUMENT_SETTINGS): case XML_ELEMENT(OFFICE, XML_DOCUMENT_CONTENT): pContext = new SwXMLDocContext_Impl( *this, nElement ); break; case XML_ELEMENT(OFFICE, XML_DOCUMENT_STYLES): pContext = new SwXMLDocStylesContext_Impl( *this, nElement ); break; } return pContext; } SwXMLImport::SwXMLImport( const uno::Reference< uno::XComponentContext >& rContext, OUString const & implementationName, SvXMLImportFlags nImportFlags) : SvXMLImport( rContext, implementationName, nImportFlags ), m_nStyleFamilyMask( SfxStyleFamily::All ), m_bLoadDoc( true ), m_bInsert( false ), m_bBlock( false ), m_bOrganizerMode( false ), m_bInititedXForms( false ), m_pDoc( nullptr ) { InitItemImport(); } SwXMLImport::~SwXMLImport() throw () { if (HasShapeImport()) { SAL_WARN("sw", "endDocument skipped, dropping shapes now to avoid dangling SvTextShapeImportHelper pointing to this"); ClearShapeImport(); } FinitItemImport(); } void SwXMLImport::setTextInsertMode( const Reference< XTextRange > & rInsertPos ) { m_bInsert = true; Reference < XText > xText = rInsertPos->getText(); Reference < XTextCursor > xTextCursor = xText->createTextCursorByRange( rInsertPos ); GetTextImport()->SetCursor( xTextCursor ); } void SwXMLImport::setStyleInsertMode( SfxStyleFamily nFamilies, bool bOverwrite ) { m_bInsert = !bOverwrite; m_nStyleFamilyMask = nFamilies; m_bLoadDoc = false; } const Sequence< sal_Int8 > & SwXMLImport::getUnoTunnelId() throw() { static const UnoTunnelIdInit theSwXMLImportUnoTunnelId; return theSwXMLImportUnoTunnelId.getSeq(); } sal_Int64 SAL_CALL SwXMLImport::getSomething( const Sequence< sal_Int8 >& rId ) { if( isUnoTunnelId(rId) ) { return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) ); } return SvXMLImport::getSomething( rId ); } static OTextCursorHelper *lcl_xml_GetSwXTextCursor( const Reference < XTextCursor >& rTextCursor ) { Reference xCursorTunnel( rTextCursor, UNO_QUERY ); OSL_ENSURE( xCursorTunnel.is(), "missing XUnoTunnel for Cursor" ); if( !xCursorTunnel.is() ) return nullptr; OTextCursorHelper *pTextCursor = reinterpret_cast< OTextCursorHelper *>( sal::static_int_cast< sal_IntPtr >( xCursorTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() ))); OSL_ENSURE( pTextCursor, "SwXTextCursor missing" ); return pTextCursor; } void SwXMLImport::startDocument() { // delegate to parent SvXMLImport::startDocument(); OSL_ENSURE( GetModel().is(), "model is missing" ); if( !GetModel().is() ) return; // this method will modify the document directly -> lock SolarMutex SolarMutexGuard aGuard; Reference< XPropertySet > xImportInfo( getImportInfo() ); Reference< XPropertySetInfo > xPropertySetInfo; if( xImportInfo.is() ) xPropertySetInfo = xImportInfo->getPropertySetInfo(); if( xPropertySetInfo.is() ) { Any aAny; // insert style mode? OUString sStyleInsertModeFamilies("StyleInsertModeFamilies"); if( xPropertySetInfo->hasPropertyByName(sStyleInsertModeFamilies) ) { aAny = xImportInfo->getPropertyValue(sStyleInsertModeFamilies); Sequence< OUString> aFamiliesSeq; if( aAny >>= aFamiliesSeq ) { SfxStyleFamily nFamilyMask = SfxStyleFamily::None; for( const OUString& rFamily : std::as_const(aFamiliesSeq) ) { if( rFamily=="FrameStyles" ) nFamilyMask |= SfxStyleFamily::Frame; else if( rFamily=="PageStyles" ) nFamilyMask |= SfxStyleFamily::Page; else if( rFamily=="CharacterStyles" ) nFamilyMask |= SfxStyleFamily::Char; else if( rFamily=="ParagraphStyles" ) nFamilyMask |= SfxStyleFamily::Para; else if( rFamily=="NumberingStyles" ) nFamilyMask |= SfxStyleFamily::Pseudo; } bool bOverwrite = false; static const OUStringLiteral sStyleInsertModeOverwrite(u"StyleInsertModeOverwrite"); if( xPropertySetInfo->hasPropertyByName(sStyleInsertModeOverwrite) ) { aAny = xImportInfo->getPropertyValue(sStyleInsertModeOverwrite); if( auto b = o3tl::tryAccess(aAny) ) { if( *b ) bOverwrite = true; } } setStyleInsertMode( nFamilyMask, bOverwrite ); } } // text insert mode? static const OUStringLiteral sTextInsertModeRange(u"TextInsertModeRange"); if( xPropertySetInfo->hasPropertyByName(sTextInsertModeRange) ) { aAny = xImportInfo->getPropertyValue(sTextInsertModeRange); Reference xInsertTextRange; if( aAny >>= xInsertTextRange ) setTextInsertMode( xInsertTextRange ); } // auto text mode static const OUStringLiteral sAutoTextMode(u"AutoTextMode"); if( xPropertySetInfo->hasPropertyByName(sAutoTextMode) ) { aAny = xImportInfo->getPropertyValue(sAutoTextMode); if( auto b = o3tl::tryAccess(aAny) ) { if( *b ) m_bBlock = true; } } // organizer mode static const OUStringLiteral sOrganizerMode(u"OrganizerMode"); if( xPropertySetInfo->hasPropertyByName(sOrganizerMode) ) { aAny = xImportInfo->getPropertyValue(sOrganizerMode); if( auto b = o3tl::tryAccess(aAny) ) { if( *b ) m_bOrganizerMode = true; } } // default document properties static const OUStringLiteral sDefSettings(u"DefaultDocumentSettings"); if (xPropertySetInfo->hasPropertyByName(sDefSettings)) { aAny = xImportInfo->getPropertyValue(sDefSettings); Sequence aProps; if (aAny >>= aProps) { Reference xFac(GetModel(), UNO_QUERY); Reference xProps( xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY); Reference xInfo(xProps->getPropertySetInfo()); if (xProps.is() && xInfo.is()) { for (const auto& rProp : std::as_const(aProps)) { if (xInfo->hasPropertyByName(rProp.Name)) { xProps->setPropertyValue(rProp.Name, rProp.Value); } } } } } } // There only is a text cursor by now if we are in insert mode. In any // other case we have to create one at the start of the document. // We also might change into the insert mode later, so we have to make // sure to first set the insert mode and then create the text import // helper. Otherwise it won't have the insert flag set! OTextCursorHelper *pTextCursor = nullptr; Reference < XTextCursor > xTextCursor; if( HasTextImport() ) xTextCursor = GetTextImport()->GetCursor(); if( !xTextCursor.is() ) { Reference < XTextDocument > xTextDoc( GetModel(), UNO_QUERY ); Reference < XText > xText = xTextDoc->getText(); xTextCursor = xText->createTextCursor(); SwCursorShell *pCursorSh = nullptr; SwDoc *pDoc = nullptr; if( SvXMLImportFlags::ALL == getImportFlags() ) { pTextCursor = lcl_xml_GetSwXTextCursor( xTextCursor ); OSL_ENSURE( pTextCursor, "SwXTextCursor missing" ); if( !pTextCursor ) return; pDoc = pTextCursor->GetDoc(); OSL_ENSURE( pDoc, "SwDoc missing" ); if( !pDoc ) return; // Is there an edit shell. If yes, then we are currently inserting // a document. We then have to insert at the current edit shell's // cursor position. That not quite clean code, but there is no other // way currently. pCursorSh = pDoc->GetEditShell(); } if( pCursorSh ) { const uno::Reference xInsertTextRange( SwXTextRange::CreateXTextRange( *pDoc, *pCursorSh->GetCursor()->GetPoint(), nullptr ) ); setTextInsertMode( xInsertTextRange ); xTextCursor = GetTextImport()->GetCursor(); pTextCursor = nullptr; } else GetTextImport()->SetCursor( xTextCursor ); } if( !(getImportFlags() & (SvXMLImportFlags::CONTENT|SvXMLImportFlags::MASTERSTYLES)) ) return; if( !pTextCursor ) pTextCursor = lcl_xml_GetSwXTextCursor( xTextCursor ); OSL_ENSURE( pTextCursor, "SwXTextCursor missing" ); if( !pTextCursor ) return; SwDoc *pDoc = pTextCursor->GetDoc(); OSL_ENSURE( pDoc, "SwDoc missing" ); if( !pDoc ) return; if (SvXMLImportFlags::ALL == getImportFlags()) { // for flat ODF - this is done in SwReader::Read() for package ODF pDoc->SetInReading(true); pDoc->SetInXMLImport(true); } if( (getImportFlags() & SvXMLImportFlags::CONTENT) && !IsStylesOnlyMode() ) { m_pSttNdIdx.reset(new SwNodeIndex( pDoc->GetNodes() )); if( IsInsertMode() ) { SwPaM *pPaM = pTextCursor->GetPaM(); const SwPosition* pPos = pPaM->GetPoint(); // Split once and remember the node that has been split. pDoc->getIDocumentContentOperations().SplitNode( *pPos, false ); *m_pSttNdIdx = pPos->nNode.GetIndex()-1; // Split again. pDoc->getIDocumentContentOperations().SplitNode( *pPos, false ); // Insert all content into the new node pPaM->Move( fnMoveBackward ); pDoc->SetTextFormatColl ( *pPaM, pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, false ) ); } } // We need a draw model to be able to set the z order pDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); // #i52858# - method name changed // SJ: #i49801# locking the model to disable repaints SwDrawModel* pDrawModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); if ( pDrawModel ) pDrawModel->setLock(true); if (!GetGraphicStorageHandler().is()) { m_xGraphicStorageHandler = SvXMLGraphicHelper::Create(SvXMLGraphicHelperMode::Read); SetGraphicStorageHandler(m_xGraphicStorageHandler); } if( !GetEmbeddedResolver().is() ) { SfxObjectShell *pPersist = pDoc->GetPersist(); if( pPersist ) { m_xEmbeddedResolver = SvXMLEmbeddedObjectHelper::Create( *pPersist, SvXMLEmbeddedObjectHelperMode::Read ); SetEmbeddedResolver( m_xEmbeddedResolver ); } } } void SwXMLImport::endDocument() { OSL_ENSURE( GetModel().is(), "model missing; maybe startDocument wasn't called?" ); if( !GetModel().is() ) return; // this method will modify the document directly -> lock SolarMutex SolarMutexGuard aGuard; if (m_xGraphicStorageHandler) m_xGraphicStorageHandler->dispose(); m_xGraphicStorageHandler.clear(); if( m_xEmbeddedResolver ) m_xEmbeddedResolver->dispose(); m_xEmbeddedResolver.clear(); // Clear the shape import to sort the shapes (and not in the // destructor that might be called after the import has finished // for Java filters. if( HasShapeImport() ) ClearShapeImport(); SwDoc *pDoc = nullptr; if( (getImportFlags() & SvXMLImportFlags::CONTENT) && !IsStylesOnlyMode() ) { Reference xCursorTunnel( GetTextImport()->GetCursor(), UNO_QUERY); assert(xCursorTunnel.is() && "missing XUnoTunnel for Cursor"); OTextCursorHelper *pTextCursor = reinterpret_cast< OTextCursorHelper *>( sal::static_int_cast< sal_IntPtr >( xCursorTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() ))); assert(pTextCursor && "SwXTextCursor missing"); SwPaM *pPaM = pTextCursor->GetPaM(); if( IsInsertMode() && m_pSttNdIdx->GetIndex() ) { // If we are in insert mode, join the split node that is in front // of the new content with the first new node. Or in other words: // Revert the first split node. SwTextNode* pTextNode = m_pSttNdIdx->GetNode().GetTextNode(); SwNodeIndex aNxtIdx( *m_pSttNdIdx ); if( pTextNode && pTextNode->CanJoinNext( &aNxtIdx ) && m_pSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex() ) { // If the PaM points to the first new node, move the PaM to the // end of the previous node. if( pPaM->GetPoint()->nNode == aNxtIdx ) { pPaM->GetPoint()->nNode = *m_pSttNdIdx; pPaM->GetPoint()->nContent.Assign( pTextNode, pTextNode->GetText().getLength()); } #if OSL_DEBUG_LEVEL > 0 // !!! This should be impossible !!!! OSL_ENSURE( m_pSttNdIdx->GetIndex()+1 != pPaM->GetBound().nNode.GetIndex(), "PaM.Bound1 point to new node " ); OSL_ENSURE( m_pSttNdIdx->GetIndex()+1 != pPaM->GetBound( false ).nNode.GetIndex(), "PaM.Bound2 points to new node" ); if( m_pSttNdIdx->GetIndex()+1 == pPaM->GetBound().nNode.GetIndex() ) { const sal_Int32 nCntPos = pPaM->GetBound().nContent.GetIndex(); pPaM->GetBound().nContent.Assign( pTextNode, pTextNode->GetText().getLength() + nCntPos ); } if( m_pSttNdIdx->GetIndex()+1 == pPaM->GetBound( false ).nNode.GetIndex() ) { const sal_Int32 nCntPos = pPaM->GetBound( false ).nContent.GetIndex(); pPaM->GetBound( false ).nContent.Assign( pTextNode, pTextNode->GetText().getLength() + nCntPos ); } #endif // If the first new node isn't empty, convert the node's text // attributes into hints. Otherwise, set the new node's // paragraph style at the previous (empty) node. SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode(); if (!pTextNode->GetText().isEmpty()) pDelNd->FormatToTextAttr( pTextNode ); else { pTextNode->ResetAttr(RES_CHRATR_BEGIN, RES_CHRATR_END); pTextNode->ChgFormatColl( pDelNd->GetTextColl() ); if (!pDelNd->GetNoCondAttr(RES_PARATR_LIST_ID, /*bInParents=*/false)) { // MergeListsAtDocumentInsertPosition() will deal with lists below, copy // paragraph direct formatting otherwise. pDelNd->CopyCollFormat(*pTextNode); } } pTextNode->JoinNext(); } } SwPosition* pPos = pPaM->GetPoint(); OSL_ENSURE( !pPos->nContent.GetIndex(), "last paragraph isn't empty" ); if( !pPos->nContent.GetIndex() ) { SwTextNode* pCurrNd; sal_uLong nNodeIdx = pPos->nNode.GetIndex(); pDoc = &pPaM->GetDoc(); OSL_ENSURE( pPos->nNode.GetNode().IsContentNode(), "insert position is not a content node" ); if( !IsInsertMode() ) { // If we're not in insert mode, the last node is deleted. const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1]; if( pPrev->IsContentNode() || ( pPrev->IsEndNode() && pPrev->StartOfSectionNode()->IsSectionNode() ) ) { SwContentNode* pCNd = pPaM->GetContentNode(); if( pCNd && pCNd->StartOfSectionIndex()+2 < pCNd->EndOfSectionIndex() ) { pPaM->GetBound().nContent.Assign( nullptr, 0 ); pPaM->GetBound(false).nContent.Assign( nullptr, 0 ); pDoc->GetNodes().Delete( pPaM->GetPoint()->nNode ); } } } else if( nullptr != (pCurrNd = pDoc->GetNodes()[nNodeIdx]->GetTextNode()) ) { // Id we're in insert mode, the empty node is joined with // the next and the previous one. if( pCurrNd->CanJoinNext( &pPos->nNode )) { SwTextNode* pNextNd = pPos->nNode.GetNode().GetTextNode(); SwNode *pLastPar = pDoc->GetNodes()[nNodeIdx -2]; if ( !pLastPar->IsTextNode() ) { pLastPar = pDoc->GetNodes()[nNodeIdx -1]; } if ( pLastPar->IsTextNode() ) { pNextNd->ChgFormatColl(pLastPar->GetTextNode()->GetTextColl()); } pPos->nContent.Assign( pNextNd, 0 ); pPaM->SetMark(); pPaM->DeleteMark(); pNextNd->JoinPrev(); // Remove line break that has been inserted by the import, // but only if one has been inserted! if( pNextNd->CanJoinPrev(/* &pPos->nNode*/ ) && *m_pSttNdIdx != pPos->nNode ) { pNextNd->JoinPrev(); } } else if (pCurrNd->GetText().isEmpty()) { pPos->nContent.Assign( nullptr, 0 ); pPaM->SetMark(); pPaM->DeleteMark(); pDoc->GetNodes().Delete( pPos->nNode ); pPaM->Move( fnMoveBackward ); } } // tdf#113877 // when we insert one document with list inside into another one with list at the insert position, // the resulting numbering in these lists is not consequent. // // Main document: // 1. One // 2. Two // 3. Three // 4. <-- insert position // // Inserted document: // 1. One // 2. Two // 3. Three // 4. // // Expected result // 1. One // 2. Two // 3. Three // 4. One // 5. Two // 6. Three // 7. // MergeListsAtDocumentInsertPosition(pDoc); } } /* Was called too early. Moved from SwXMLBodyContext_Impl::EndElement */ GetTextImport()->RedlineAdjustStartNodeCursor(); if( (getImportFlags() & SvXMLImportFlags::CONTENT) || ((getImportFlags() & SvXMLImportFlags::MASTERSTYLES) && IsStylesOnlyMode()) ) { // pDoc might be 0. In this case UpdateTextCollCondition is looking // for it itself. UpdateTextCollConditions( pDoc ); } GetTextImport()->ResetCursor(); m_pSttNdIdx.reset(); // SJ: #i49801# -> now permitting repaints if ( pDoc ) { if( getImportFlags() == SvXMLImportFlags::ALL ) { // Notify math objects. If we are in the package filter this will // be done by the filter object itself if( IsInsertMode() ) pDoc->PrtOLENotify( false ); else if ( pDoc->IsOLEPrtNotifyPending() ) pDoc->PrtOLENotify( true ); assert(pDoc->IsInReading()); assert(pDoc->IsInXMLImport()); pDoc->SetInReading(false); pDoc->SetInXMLImport(false); } SwDrawModel* pDrawModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel(); if ( pDrawModel ) pDrawModel->setLock(false); } // #i90243# if ( m_bInititedXForms ) { Reference< xforms::XFormsSupplier > xFormsSupp( GetModel(), UNO_QUERY ); Reference< XNameAccess > xXForms; if ( xFormsSupp.is() ) xXForms = xFormsSupp->getXForms().get(); if ( xXForms.is() ) { try { Sequence< beans::PropertyValue > aXFormsSettings; const OUString& sXFormsSettingsName( GetXMLToken( XML_XFORM_MODEL_SETTINGS ) ); if ( m_xLateInitSettings.is() && m_xLateInitSettings->hasByName( sXFormsSettingsName ) ) { OSL_VERIFY( m_xLateInitSettings->getByName( sXFormsSettingsName ) >>= aXFormsSettings ); applyXFormsSettings( xXForms, aXFormsSettings ); } } catch( const Exception& ) { } } } #if 1 if (!pDoc) { pDoc = SwImport::GetDocFromXMLImport(*this); } for (sal_uLong i = 0; i < pDoc->GetNodes().Count(); ++i) { if (SwTableNode *const pTableNode = pDoc->GetNodes()[i]->GetTableNode()) { if (!pTableNode->GetTable().IsNewModel() && pTableNode->GetTable().CanConvertSubtables()) { pTableNode->GetTable().ConvertSubtables(); } } // don't skip to the end; nested tables could have subtables too... } #endif // delegate to parent: takes care of error handling SvXMLImport::endDocument(); ClearTextImport(); } // tdf#113877 // when we insert one document with list inside into another one with list at the insert position, // the resulting numbering in these lists is not consequent. // // CASE-1: Main document: // 1. One // 2. Two // 3. Three // 4. <-- insert position // // Inserted document: // 1. One // 2. Two // 3. Three // 4. // // Expected result // 1. One // 2. Two // 3. Three // 4. One // 5. Two // 6. Three // 7. // // CASE-2: Main document: // 1. One // 2. Two // 3. Three // 4. <-- insert position // // Inserted document: // A) One // B) Two // C) Three // D) // // Expected result // 1. One // 2. Two // 3. Three // 4. One // A) Two // B) Three // 5. // void SwXMLImport::MergeListsAtDocumentInsertPosition(SwDoc *pDoc) { // 1. check environment if (! pDoc) return; if (! IsInsertMode() || ! m_pSttNdIdx->GetIndex()) return; sal_uLong index = 1; // the last node of the main document where we have inserted a document const SwNodePtr node1 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + 0]; // the first node of the inserted document SwNodePtr node2 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + index]; if (! (node1 && node2 && (node1->GetNodeType() == node2->GetNodeType()) && (node1->IsTextNode() == node2->IsTextNode()) )) { // not a text node at insert position return; } // 2. get the first node of the inserted document, // which will be used to detect if inside inserted document a new list was started after the first list const SfxPoolItem* pListId2Initial = nullptr; { SwContentNode* contentNode1 = static_cast(node1); SwContentNode* contentNode2 = static_cast(node2); // check if both lists have the same list properties const SfxPoolItem* pListId1 = contentNode1->GetNoCondAttr( RES_PARATR_LIST_ID, false ); const SfxPoolItem* pListId2 = contentNode2->GetNoCondAttr( RES_PARATR_LIST_ID, false ); if (! pListId1) return; if (! pListId2) return; auto pStringListId1 = dynamic_cast(pListId1); assert(pStringListId1); const OUString& sListId1 = pStringListId1->GetValue(); auto pStringListId2 = dynamic_cast(pListId2); assert(pStringListId2); const OUString& sListId2 = pStringListId2->GetValue(); const SwList* pList1 = pDoc->getIDocumentListsAccess().getListByName( sListId1 ); const SwList* pList2 = pDoc->getIDocumentListsAccess().getListByName( sListId2 ); if (! pList1) return; if (! pList2) return; const OUString& sDefaultListStyleName1 = pList1->GetDefaultListStyleName(); const OUString& sDefaultListStyleName2 = pList2->GetDefaultListStyleName(); if (sDefaultListStyleName1 != sDefaultListStyleName2) { const SwNumRule* pNumRule1 = pDoc->FindNumRulePtr( sDefaultListStyleName1 ); const SwNumRule* pNumRule2 = pDoc->FindNumRulePtr( sDefaultListStyleName2 ); if (pNumRule1 && pNumRule2) { // check style of the each list level for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) { if( pNumRule1->Get( n ) != pNumRule2->Get( n ) ) { return; } } // our list should be merged pListId2Initial = pListId2; } } else { // our list should be merged pListId2Initial = pListId2; } } if (! pListId2Initial) { // two lists have different styles => they should not be merged return; } // 3. merge two lists while ( node1 && node2 && (node1->GetNodeType() == node2->GetNodeType()) && (node1->IsTextNode() == node2->IsTextNode()) ) { SwContentNode* contentNode1 = static_cast( node1 ); SwContentNode* contentNode2 = static_cast( node2 ); const SfxPoolItem* pListId1 = contentNode1->GetNoCondAttr( RES_PARATR_LIST_ID, false ); const SfxPoolItem* pListId2 = contentNode2->GetNoCondAttr( RES_PARATR_LIST_ID, false ); if (! pListId1) return; if (! pListId2) return; if (*pListId2Initial != *pListId2) { // no more list items of the first list inside inserted document return; } // set list style to this list element contentNode2->SetAttr(*pListId1); // get next item index++; if (index >= pDoc->GetNodes().Count()) { // no more items return; } node2 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + index]; } } namespace { // Locally derive XMLTextShapeImportHelper, so we can take care of the // form import This is Writer, but not text specific, so it should go // here! class SvTextShapeImportHelper : public XMLTextShapeImportHelper { // hold own reference form import helper, because the SvxImport // stored in the superclass, from whom we originally got the // reference, is already destroyed when we want to use it in the // destructor rtl::Reference< ::xmloff::OFormLayerXMLImport > rFormImport; // hold reference to the one page (if it exists) for calling startPage() // and endPage. If !xPage.is(), then this document doesn't have a // XDrawPage. Reference xPage; public: explicit SvTextShapeImportHelper(SvXMLImport& rImp); virtual ~SvTextShapeImportHelper() override; }; } SvTextShapeImportHelper::SvTextShapeImportHelper(SvXMLImport& rImp) : XMLTextShapeImportHelper(rImp) { Reference xSupplier(rImp.GetModel(),UNO_QUERY); if (xSupplier.is()) { if (rImp.GetFormImport().is()) { rImp.GetFormImport()->startPage(xSupplier->getDrawPage()); rFormImport = rImp.GetFormImport(); } xPage = xSupplier->getDrawPage(); XMLShapeImportHelper::startPage( xPage ); } } SvTextShapeImportHelper::~SvTextShapeImportHelper() { rFormImport->endPage(); if (xPage.is()) { XMLShapeImportHelper::endPage(xPage); } } XMLTextImportHelper* SwXMLImport::CreateTextImport() { return new SwXMLTextImportHelper( GetModel(), *this, getImportInfo(), IsInsertMode(), IsStylesOnlyMode(), IsBlockMode(), m_bOrganizerMode ); } XMLShapeImportHelper* SwXMLImport::CreateShapeImport() { return new SvTextShapeImportHelper( *this ); } SvXMLImportContext *SwXMLImport::CreateFontDeclsContext() { XMLFontStylesContext *pFSContext = new XMLFontStylesContext( *this, osl_getThreadTextEncoding() ); SetFontDecls( pFSContext ); return pFSContext; } void SwXMLImport::SetViewSettings(const Sequence < PropertyValue > & aViewProps) { if (IsInsertMode() || IsStylesOnlyMode() || IsBlockMode() || m_bOrganizerMode || !GetModel().is() ) return; // this method will modify the document directly -> lock SolarMutex SolarMutexGuard aGuard; SwDoc *pDoc = getDoc(); tools::Rectangle aRect; if( pDoc->GetDocShell() ) aRect = pDoc->GetDocShell()->GetVisArea( ASPECT_CONTENT ); //TODO/LATER: why that cast?! //aRect = ((SfxInPlaceObject *)pDoc->GetDocShell())->GetVisArea(); sal_Int64 nTmp = 0; bool bShowRedlineChanges = false, bBrowseMode = false; bool bChangeShowRedline = false, bChangeBrowseMode = false; //TODO/LATER: why that cast?! bool bTwip = pDoc->GetDocShell()->GetMapUnit ( ) == MapUnit::MapTwip; //sal_Bool bTwip = pDoc->GetDocShell()->SfxInPlaceObject::GetMapUnit ( ) == MapUnit::MapTwip; for (const PropertyValue& rValue : aViewProps) { if ( rValue.Name == "ViewAreaTop" ) { rValue.Value >>= nTmp; aRect.setY( static_cast< tools::Long >(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp) ); } else if ( rValue.Name == "ViewAreaLeft" ) { rValue.Value >>= nTmp; aRect.setX( static_cast< tools::Long >(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp) ); } else if ( rValue.Name == "ViewAreaWidth" ) { rValue.Value >>= nTmp; Size aSize( aRect.GetSize() ); aSize.setWidth( static_cast< tools::Long >(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp) ); aRect.SetSize( aSize ); } else if ( rValue.Name == "ViewAreaHeight" ) { rValue.Value >>= nTmp; Size aSize( aRect.GetSize() ); aSize.setHeight( static_cast< tools::Long >(bTwip ? sanitiseMm100ToTwip(nTmp) : nTmp) ); aRect.SetSize( aSize ); } else if ( rValue.Name == "ShowRedlineChanges" ) { bShowRedlineChanges = *o3tl::doAccess(rValue.Value); bChangeShowRedline = true; } // Headers and footers are not displayed in BrowseView anymore else if ( rValue.Name == "InBrowseMode" ) { bBrowseMode = *o3tl::doAccess(rValue.Value); bChangeBrowseMode = true; } } if( pDoc->GetDocShell() ) pDoc->GetDocShell()->SetVisArea ( aRect ); if (bChangeBrowseMode) pDoc->getIDocumentSettingAccess().set(DocumentSettingId::BROWSE_MODE, bBrowseMode ); if (bChangeShowRedline) GetTextImport()->SetShowChanges( bShowRedlineChanges ); } // Note: this will be called only if there are OOo elements in settings.xml. // So if a setting is missing there we can assume that it was written // by an OOo/LO version that is older than the introduction of the setting! void SwXMLImport::SetConfigurationSettings(const Sequence < PropertyValue > & aConfigProps) { // this method will modify the document directly -> lock SolarMutex SolarMutexGuard aGuard; Reference< lang::XMultiServiceFactory > xFac( GetModel(), UNO_QUERY ); if( !xFac.is() ) return; Reference< XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY ); if( !xProps.is() ) return; Reference< XPropertySetInfo > xInfo( xProps->getPropertySetInfo() ); if( !xInfo.is() ) return; std::unordered_set< OUString > aExcludeAlways; aExcludeAlways.insert("LinkUpdateMode"); // this should contain things that are actually user-settable, via Tools->Options std::unordered_set< OUString > aExcludeWhenNotLoadingUserSettings { "ForbiddenCharacters", "IsKernAsianPunctuation", "CharacterCompressionType", "FieldAutoUpdate", "ChartAutoUpdate", "AddParaTableSpacing", "AddParaTableSpacingAtStart", "PrintAnnotationMode", "PrintBlackFonts", "PrintControls", "PrintDrawings", "PrintGraphics", "PrintHiddenText", "PrintLeftPages", "PrintPageBackground", "PrintProspect", "PrintReversed", "PrintRightPages", "PrintFaxName", "PrintPaperFromSetup", "PrintTables", "PrintTextPlaceholder", "PrintSingleJobs", "UpdateFromTemplate", "PrinterIndependentLayout", "PrintEmptyPages", "ConsiderTextWrapOnObjPos", "DoNotJustifyLinesWithManualBreak", "ProtectForm", "MsWordCompTrailingBlanks", "SubtractFlysAnchoredAtFlys", "EmptyDbFieldHidesPara" }; SvtSaveOptions aSaveOpt; bool bAreUserSettingsFromDocument = aSaveOpt.IsLoadUserSettings(); // for some properties we don't want to use the application // default if they're missing. So we watch for them in the loop // below, and set them if not found bool bPrinterIndependentLayout = false; bool bUseOldNumbering = false; bool bAddExternalLeading = false; bool bAddParaSpacingToTableCells = false; bool bAddParaLineSpacingToTableCells = false; bool bUseFormerLineSpacing = false; bool bUseFormerObjectPositioning = false; bool bUseFormerTextWrapping = false; bool bConsiderWrapOnObjPos = false; bool bIgnoreFirstLineIndentInNumbering = false; bool bDoNotJustifyLinesWithManualBreak = false; bool bDoNotResetParaAttrsForNumFont = false; bool bLoadReadonly = false; bool bDoNotCaptureDrawObjsOnPage( false ); bool bClipAsCharacterAnchoredWriterFlyFrames( false ); bool bUnixForceZeroExtLeading = false; bool bSmallCapsPercentage66 = false; bool bTabOverflow = false; bool bUnbreakableNumberings = false; bool bClippedPictures = false; bool bBackgroundParaOverDrawings = false; bool bTabOverMargin = false; bool bTabOverMarginValue = false; bool bPropLineSpacingShrinksFirstLine = false; bool bSubtractFlysAnchoredAtFlys = false; bool bEmptyDbFieldHidesPara = false; bool bCollapseEmptyCellPara = false; const PropertyValue* currentDatabaseDataSource = nullptr; const PropertyValue* currentDatabaseCommand = nullptr; const PropertyValue* currentDatabaseCommandType = nullptr; const PropertyValue* embeddedDatabaseName = nullptr; for( const PropertyValue& rValue : aConfigProps ) { bool bSet = aExcludeAlways.find(rValue.Name) == aExcludeAlways.end(); if( bSet && !bAreUserSettingsFromDocument && (aExcludeWhenNotLoadingUserSettings.find(rValue.Name) != aExcludeWhenNotLoadingUserSettings.end()) ) { bSet = false; } if( bSet ) { try { if( xInfo->hasPropertyByName( rValue.Name ) ) { if( rValue.Name == "RedlineProtectionKey" ) { Sequence aKey; rValue.Value >>= aKey; GetTextImport()->SetChangesProtectionKey( aKey ); } else { // HACK: Setting these out of order does not work. if( rValue.Name == "CurrentDatabaseDataSource" ) currentDatabaseDataSource = &rValue; else if( rValue.Name == "CurrentDatabaseCommand" ) currentDatabaseCommand = &rValue; else if( rValue.Name == "CurrentDatabaseCommandType" ) currentDatabaseCommandType = &rValue; else if (rValue.Name == "EmbeddedDatabaseName") embeddedDatabaseName = &rValue; else xProps->setPropertyValue( rValue.Name, rValue.Value ); } } // did we find any of the non-default cases? if ( rValue.Name == "PrinterIndependentLayout" ) bPrinterIndependentLayout = true; else if ( rValue.Name == "AddExternalLeading" ) bAddExternalLeading = true; else if ( rValue.Name == "AddParaSpacingToTableCells" ) bAddParaSpacingToTableCells = true; else if ( rValue.Name == "AddParaLineSpacingToTableCells" ) bAddParaLineSpacingToTableCells = true; else if ( rValue.Name == "UseFormerLineSpacing" ) bUseFormerLineSpacing = true; else if ( rValue.Name == "UseFormerObjectPositioning" ) bUseFormerObjectPositioning = true; else if ( rValue.Name == "UseFormerTextWrapping" ) bUseFormerTextWrapping = true; else if ( rValue.Name == "UseOldNumbering" ) bUseOldNumbering = true; else if ( rValue.Name == "ConsiderTextWrapOnObjPos" ) bConsiderWrapOnObjPos = true; else if ( rValue.Name == "IgnoreFirstLineIndentInNumbering" ) bIgnoreFirstLineIndentInNumbering = true; else if ( rValue.Name == "DoNotJustifyLinesWithManualBreak" ) bDoNotJustifyLinesWithManualBreak = true; else if ( rValue.Name == "DoNotResetParaAttrsForNumFont" ) bDoNotResetParaAttrsForNumFont = true; else if ( rValue.Name == "LoadReadonly" ) bLoadReadonly = true; else if ( rValue.Name == "DoNotCaptureDrawObjsOnPage" ) bDoNotCaptureDrawObjsOnPage = true; else if ( rValue.Name == "ClipAsCharacterAnchoredWriterFlyFrames" ) bClipAsCharacterAnchoredWriterFlyFrames = true; else if ( rValue.Name == "UnxForceZeroExtLeading" ) bUnixForceZeroExtLeading = true; else if ( rValue.Name == "SmallCapsPercentage66" ) bSmallCapsPercentage66 = true; else if ( rValue.Name == "TabOverflow" ) bTabOverflow = true; else if ( rValue.Name == "UnbreakableNumberings" ) bUnbreakableNumberings = true; else if ( rValue.Name == "ClippedPictures" ) bClippedPictures = true; else if ( rValue.Name == "BackgroundParaOverDrawings" ) bBackgroundParaOverDrawings = true; else if ( rValue.Name == "TabOverMargin" ) { bTabOverMargin = true; rValue.Value >>= bTabOverMarginValue; } else if ( rValue.Name == "PropLineSpacingShrinksFirstLine" ) bPropLineSpacingShrinksFirstLine = true; else if (rValue.Name == "SubtractFlysAnchoredAtFlys") bSubtractFlysAnchoredAtFlys = true; else if (rValue.Name == "EmptyDbFieldHidesPara") bEmptyDbFieldHidesPara = true; else if (rValue.Name == "CollapseEmptyCellPara") bCollapseEmptyCellPara = true; } catch( Exception& ) { TOOLS_WARN_EXCEPTION( "sw", "SwXMLImport::SetConfigurationSettings" ); } } } try { if( currentDatabaseDataSource != nullptr ) xProps->setPropertyValue( currentDatabaseDataSource->Name, currentDatabaseDataSource->Value ); if( currentDatabaseCommand != nullptr ) xProps->setPropertyValue( currentDatabaseCommand->Name, currentDatabaseCommand->Value ); if( currentDatabaseCommandType != nullptr ) xProps->setPropertyValue( currentDatabaseCommandType->Name, currentDatabaseCommandType->Value ); if (embeddedDatabaseName) xProps->setPropertyValue(embeddedDatabaseName->Name, embeddedDatabaseName->Value); } catch( Exception& ) { TOOLS_WARN_EXCEPTION( "sw", "SwXMLImport::SetConfigurationSettings" ); } // finally, treat the non-default cases // introduce boolean, that indicates a document, written by version prior SO8. // If user settings are not loaded, we can't know if this is an old document. Better to assume no? const bool bDocumentPriorSO8 = !bConsiderWrapOnObjPos && bAreUserSettingsFromDocument; // Use old behaviour if this setting didn't exist, but only if this setting is being read from the document. // (Obviously the setting doesn't exist if we are explicitly ignoring it, so then stick with program/user defaults) if(!bPrinterIndependentLayout && bAreUserSettingsFromDocument) { xProps->setPropertyValue( "PrinterIndependentLayout", Any(sal_Int16(document::PrinterIndependentLayout::DISABLED)) ); } if( ! bAddExternalLeading ) { xProps->setPropertyValue( "AddExternalLeading", makeAny( false ) ); } if( ! bUseFormerLineSpacing ) { xProps->setPropertyValue( "UseFormerLineSpacing", makeAny( true ) ); } if( !bUseFormerObjectPositioning ) { xProps->setPropertyValue( "UseFormerObjectPositioning", makeAny( true ) ); } if( !bUseOldNumbering ) { xProps->setPropertyValue( "UseOldNumbering", makeAny(true) ); } if( !bAddParaSpacingToTableCells ) { xProps->setPropertyValue( "AddParaSpacingToTableCells", makeAny( false ) ); } if (!bAddParaLineSpacingToTableCells) { xProps->setPropertyValue("AddParaLineSpacingToTableCells", makeAny(false)); } if( !bUseFormerTextWrapping ) { xProps->setPropertyValue( "UseFormerTextWrapping", makeAny( true ) ); } if (!bConsiderWrapOnObjPos && bAreUserSettingsFromDocument) { xProps->setPropertyValue( "ConsiderTextWrapOnObjPos", makeAny( false ) ); } // #i47448# // For SO7pp4, part of the 'new numbering' stuff has been backported from // SO8. Unfortunately, only part of it and by using the same compatibility option // like in SO8. Therefore documents generated with SO7pp4, containing // numbered paragraphs with first line indent differ between SO7pp4 and // SO8. In order to fix this for SO8pp1, I introduce a new compatibility // flag 'bIgnoreFirstLineIndentInNumbering'. This flag has to be set for all // documents < SO8, but not for SO8. So if the property is not present, the // flag will be set to 'true'. SO8 documents surely have the // 'ConsiderWrapOnObjPos' property set (no matter if 'true' or 'false'), // therefore the correct condition to set this flag is this: if( !bIgnoreFirstLineIndentInNumbering && bDocumentPriorSO8 ) { xProps->setPropertyValue( "IgnoreFirstLineIndentInNumbering", makeAny( true ) ); } // This flag has to be set for all documents < SO8 if ( !bDoNotJustifyLinesWithManualBreak && bDocumentPriorSO8 ) { xProps->setPropertyValue( "DoNotJustifyLinesWithManualBreak", makeAny( true ) ); } // This flag has to be set for all documents < SO8 if ( !bDoNotResetParaAttrsForNumFont && bDocumentPriorSO8 ) { xProps->setPropertyValue( "DoNotResetParaAttrsForNumFont", makeAny( true ) ); } if ( !bLoadReadonly ) { xProps->setPropertyValue( "LoadReadonly", makeAny( false ) ); } // This flag has to be set for all documents < SO8 if ( !bDoNotCaptureDrawObjsOnPage && bDocumentPriorSO8 ) { xProps->setPropertyValue( "DoNotCaptureDrawObjsOnPage", makeAny( true ) ); } // This flag has to be set for all documents < SO8 if ( !bClipAsCharacterAnchoredWriterFlyFrames && bDocumentPriorSO8 ) { xProps->setPropertyValue( "ClipAsCharacterAnchoredWriterFlyFrames", makeAny( true ) ); } if ( !bUnixForceZeroExtLeading ) { xProps->setPropertyValue( "UnxForceZeroExtLeading", makeAny( true ) ); } // Old LO versions had 66 as the value for small caps percentage, later changed to 80. // In order to keep backwards compatibility, SmallCapsPercentage66 option is written to .odt // files, and the default for new documents is 'false'. Files without this option // are considered to be old files, so set the compatibility option too. if ( !bSmallCapsPercentage66 ) { xProps->setPropertyValue( "SmallCapsPercentage66", makeAny( true ) ); } if ( !bTabOverflow ) { xProps->setPropertyValue( "TabOverflow", makeAny( false ) ); } if ( !bUnbreakableNumberings ) { xProps->setPropertyValue( "UnbreakableNumberings", makeAny( false ) ); } if ( !bClippedPictures ) { xProps->setPropertyValue( "ClippedPictures", makeAny( false ) ); } if ( !bBackgroundParaOverDrawings ) xProps->setPropertyValue("BackgroundParaOverDrawings", makeAny( false ) ); if ( !bTabOverMargin ) xProps->setPropertyValue("TabOverMargin", makeAny( false ) ); if (bTabOverMarginValue) // Let TabOverMargin imply the new default for // PrinterIndependentLayout, knowing the first is set by Word import // filters and Word defaults to our new default as well. xProps->setPropertyValue( "PrinterIndependentLayout", uno::Any(document::PrinterIndependentLayout::HIGH_RESOLUTION)); if (!bPropLineSpacingShrinksFirstLine) xProps->setPropertyValue("PropLineSpacingShrinksFirstLine", makeAny(false)); if (!bSubtractFlysAnchoredAtFlys && bAreUserSettingsFromDocument) xProps->setPropertyValue("SubtractFlysAnchoredAtFlys", makeAny(true)); if (!bEmptyDbFieldHidesPara && bAreUserSettingsFromDocument) xProps->setPropertyValue("EmptyDbFieldHidesPara", makeAny(false)); if (!bCollapseEmptyCellPara) xProps->setPropertyValue("CollapseEmptyCellPara", makeAny(false)); SwDoc *pDoc = getDoc(); SfxPrinter *pPrinter = pDoc->getIDocumentDeviceAccess().getPrinter( false ); if( pPrinter ) { // If the printer is known, then the OLE objects will // already have correct sizes, and we don't have to call // PrtOLENotify again. Otherwise we have to call it. // The flag might be set from setting the printer, so it // it is required to clear it. pDoc->SetOLEPrtNotifyPending( !pPrinter->IsKnown() ); } } void SwXMLImport::SetDocumentSpecificSettings( const OUString& _rSettingsGroupName, const Sequence< PropertyValue>& _rSettings ) { // the only doc-specific settings group we know so far are the XForms settings if ( !IsXMLToken( _rSettingsGroupName, XML_XFORM_MODEL_SETTINGS ) ) return; // preserve the settings for a later iteration - we are currently reading the settings.xml, // the content.xml will be read later, by another instance of SwXMLImport OSL_ENSURE( m_xLateInitSettings.is(), "SwXMLImport::SetDocumentSpecificSettings: no storage for those settings!" ); if ( !m_xLateInitSettings.is() ) return; try { if ( m_xLateInitSettings->hasByName( _rSettingsGroupName ) ) { m_xLateInitSettings->replaceByName( _rSettingsGroupName, makeAny( _rSettings ) ); OSL_FAIL( "SwXMLImport::SetDocumentSpecificSettings: already have settings for this model!" ); } else m_xLateInitSettings->insertByName( _rSettingsGroupName, makeAny( _rSettings ) ); } catch( const Exception& ) { } } void SwXMLImport::initialize( const Sequence& aArguments ) { // delegate to super class SvXMLImport::initialize(aArguments); // we are only looking for a NamedValue "LateInitSettings" for(const auto& rArgument : aArguments) { beans::NamedValue aNamedValue; if ( rArgument >>= aNamedValue ) { if (aNamedValue.Name == "LateInitSettings") { OSL_VERIFY( aNamedValue.Value >>= m_xLateInitSettings ); } } } } SwDoc* SwImport::GetDocFromXMLImport( SvXMLImport const & rImport ) { auto pTextDoc = comphelper::getUnoTunnelImplementation(rImport.GetModel()); assert( pTextDoc ); assert( pTextDoc->GetDocShell() ); SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); OSL_ENSURE( pDoc, "Where is my document?" ); return pDoc; } void SwXMLImport::initXForms() { // obtain SwDoc auto pXTextDocument = comphelper::getUnoTunnelImplementation(GetModel()); if( pXTextDocument == nullptr ) return; SwDoc *pDoc = pXTextDocument->GetDocShell()->GetDoc(); // init XForms (if not already done) // (no default model, since we'll load the models) if( ! pDoc->isXForms() ) pDoc->initXForms( false ); m_bInititedXForms = true; } SwDoc* SwXMLImport::getDoc() { if( m_pDoc != nullptr ) return m_pDoc; Reference < XTextDocument > xTextDoc( GetModel(), UNO_QUERY ); Reference < XText > xText = xTextDoc->getText(); Reference xTextTunnel( xText, UNO_QUERY); assert( xTextTunnel.is()); SwXText *pText = reinterpret_cast< SwXText *>( sal::static_int_cast< sal_IntPtr >( xTextTunnel->getSomething( SwXText::getUnoTunnelId() ))); assert( pText != nullptr ); m_pDoc = pText->GetDoc(); assert( m_pDoc != nullptr ); return m_pDoc; } const SwDoc* SwXMLImport::getDoc() const { return const_cast< SwXMLImport* >( this )->getDoc(); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_Writer_XMLOasisImporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const &) { return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisImporter", SvXMLImportFlags::ALL)); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_Writer_XMLOasisStylesImporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const &) { return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisStylesImporter", SvXMLImportFlags::STYLES | SvXMLImportFlags::MASTERSTYLES | SvXMLImportFlags::AUTOSTYLES | SvXMLImportFlags::FONTDECLS)); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_Writer_XMLOasisContentImporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const &) { return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisContentImporter", SvXMLImportFlags::CONTENT | SvXMLImportFlags::SCRIPTS | SvXMLImportFlags::AUTOSTYLES | SvXMLImportFlags::FONTDECLS)); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_Writer_XMLOasisMetaImporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const &) { return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisMetaImporter", SvXMLImportFlags::META)); } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_Writer_XMLOasisSettingsImporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const &) { return cppu::acquire(new SwXMLImport(context, "com.sun.star.comp.Writer.XMLOasisSettingsImporter", SvXMLImportFlags::SETTINGS)); } extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportFODT(SvStream &rStream) { SwGlobals::ensure(); SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL)); xDocSh->DoInitNew(); uno::Reference xModel(xDocSh->GetModel()); uno::Reference xMultiServiceFactory(comphelper::getProcessServiceFactory()); uno::Reference xStream(new utl::OSeekableInputStreamWrapper(rStream)); uno::Reference xInterface(xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.XmlFilterAdaptor"), uno::UNO_SET_THROW); css::uno::Sequence aUserData(7); aUserData[0] = "com.sun.star.comp.filter.OdfFlatXml"; aUserData[2] = "com.sun.star.comp.Writer.XMLOasisImporter"; aUserData[3] = "com.sun.star.comp.Writer.XMLOasisExporter"; aUserData[6] = "true"; uno::Sequence aAdaptorArgs(comphelper::InitPropertySequence( { { "UserData", uno::Any(aUserData) }, })); css::uno::Sequence aOuterArgs(1); aOuterArgs[0] <<= aAdaptorArgs; uno::Reference xInit(xInterface, uno::UNO_QUERY_THROW); xInit->initialize(aOuterArgs); uno::Reference xImporter(xInterface, uno::UNO_QUERY_THROW); uno::Sequence aArgs(comphelper::InitPropertySequence( { { "InputStream", uno::Any(xStream) }, { "URL", uno::Any(OUString("private:stream")) }, })); xImporter->setTargetDocument(xModel); uno::Reference xFilter(xInterface, uno::UNO_QUERY_THROW); //SetLoading hack because the document properties will be re-initted //by the xml filter and during the init, while it's considered uninitialized, //setting a property will inform the document it's modified, which attempts //to update the properties, which throws cause the properties are uninitialized xDocSh->SetLoading(SfxLoadedFlags::NONE); bool ret = xFilter->filter(aArgs); xDocSh->SetLoading(SfxLoadedFlags::ALL); xDocSh->DoClose(); return ret; } extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDOCX(SvStream &rStream) { SwGlobals::ensure(); SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL)); xDocSh->DoInitNew(); uno::Reference xModel(xDocSh->GetModel()); uno::Reference xMultiServiceFactory(comphelper::getProcessServiceFactory()); uno::Reference xStream(new utl::OSeekableInputStreamWrapper(rStream)); uno::Reference xFilter(xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.WriterFilter"), uno::UNO_QUERY_THROW); uno::Reference xImporter(xFilter, uno::UNO_QUERY_THROW); uno::Sequence aArgs(comphelper::InitPropertySequence( { { "InputStream", uno::makeAny(xStream) }, { "InputMode", uno::makeAny(true) }, })); xImporter->setTargetDocument(xModel); //SetLoading hack because the document properties will be re-initted //by the xml filter and during the init, while it's considered uninitialized, //setting a property will inform the document it's modified, which attempts //to update the properties, which throws cause the properties are uninitialized xDocSh->SetLoading(SfxLoadedFlags::NONE); bool ret = false; try { ret = xFilter->filter(aArgs); } catch (...) { } xDocSh->SetLoading(SfxLoadedFlags::ALL); xDocSh->DoClose(); return ret; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */