/* -*- 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 <DocumentLinksAdministrationManager.hxx>
#include <doc.hxx>
#include <DocumentSettingManager.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentState.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentMarkAccess.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/frame.hxx>
#include <linkenum.hxx>
#include <com/sun/star/document/UpdateDocMode.hpp>
#include <swtypes.hxx>
#include <viewsh.hxx>
#include <docsh.hxx>
#include <bookmrk.hxx>
#include <swserv.hxx>
#include <swbaslnk.hxx>
#include <section.hxx>
#include <docary.hxx>
#include <frmfmt.hxx>
#include <fmtcntnt.hxx>
#include <swtable.hxx>
#include <ndtxt.hxx>
#include <tools/urlobj.hxx>
#include <unotools/charclass.hxx>
#include <unotools/securityoptions.hxx>
using namespace ::com::sun::star;
//Helper functions for this file
namespace
{
struct FindItem
{
const OUString m_Item;
SwTableNode* pTableNd;
SwSectionNode* pSectNd;
explicit FindItem(const OUString& rS)
: m_Item(rS), pTableNd(nullptr), pSectNd(nullptr)
{}
};
::sfx2::SvBaseLink* lcl_FindNextRemovableLink( const ::sfx2::SvBaseLinks& rLinks )
{
for(const auto & rLink : rLinks)
{
::sfx2::SvBaseLink* pLnk = &(*rLink);
if( pLnk &&
( OBJECT_CLIENT_GRF == pLnk->GetObjType() ||
OBJECT_CLIENT_FILE == pLnk->GetObjType() ) &&
dynamic_cast<const SwBaseLink*>( pLnk) != nullptr )
{
tools::SvRef<sfx2::SvBaseLink> xLink = pLnk;
OUString sFName;
sfx2::LinkManager::GetDisplayNames( xLink.get(), nullptr, &sFName );
INetURLObject aURL( sFName );
if( INetProtocol::File == aURL.GetProtocol() ||
INetProtocol::Cid == aURL.GetProtocol() )
return pLnk;
}
}
return nullptr;
}
::sw::mark::DdeBookmark* lcl_FindDdeBookmark( const IDocumentMarkAccess& rMarkAccess, const OUString& rName, const bool bCaseSensitive )
{
//Iterating over all bookmarks, checking DdeBookmarks
const OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lowercase(rName);
for(IDocumentMarkAccess::const_iterator_t ppMark = rMarkAccess.getAllMarksBegin();
ppMark != rMarkAccess.getAllMarksEnd();
++ppMark)
{
if (::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(ppMark->get()))
{
if (
(bCaseSensitive && (pBkmk->GetName() == sNameLc)) ||
(!bCaseSensitive && GetAppCharClass().lowercase(pBkmk->GetName()) == sNameLc)
)
{
return pBkmk;
}
}
}
return nullptr;
}
bool lcl_FindSection( const SwSectionFormat* pSectFormat, FindItem * const pItem, bool bCaseSensitive )
{
SwSection* pSect = pSectFormat->GetSection();
if( pSect )
{
OUString sNm( bCaseSensitive
? pSect->GetSectionName()
: GetAppCharClass().lowercase( pSect->GetSectionName() ));
OUString sCompare( bCaseSensitive
? pItem->m_Item
: GetAppCharClass().lowercase( pItem->m_Item ) );
if( sNm == sCompare )
{
// found, so get the data
const SwNodeIndex* pIdx;
if( nullptr != (pIdx = pSectFormat->GetContent().GetContentIdx() ) &&
&pSectFormat->GetDoc()->GetNodes() == &pIdx->GetNodes() )
{
// a table in the normal NodesArr
pItem->pSectNd = pIdx->GetNode().GetSectionNode();
return false;
}
// If the name is already correct, but not the rest then we don't have them.
// The names are always unique.
}
}
return true;
}
bool lcl_FindTable( const SwFrameFormat* pTableFormat, FindItem * const pItem )
{
OUString sNm( GetAppCharClass().lowercase( pTableFormat->GetName() ));
if ( sNm == pItem->m_Item )
{
SwTable* pTmpTable;
SwTableBox* pFBox;
if( nullptr != ( pTmpTable = SwTable::FindTable( pTableFormat ) ) &&
nullptr != ( pFBox = pTmpTable->GetTabSortBoxes()[0] ) &&
pFBox->GetSttNd() &&
&pTableFormat->GetDoc()->GetNodes() == &pFBox->GetSttNd()->GetNodes() )
{
// a table in the normal NodesArr
pItem->pTableNd = const_cast<SwTableNode*>(
pFBox->GetSttNd()->FindTableNode());
return false;
}
// If the name is already correct, but not the rest then we don't have them.
// The names are always unique.
}
return true;
}
}
namespace sw
{
DocumentLinksAdministrationManager::DocumentLinksAdministrationManager( SwDoc& i_rSwdoc )
: mbVisibleLinks(true)
, mbLinksUpdated( false ) //#i38810#
, m_pLinkMgr( new sfx2::LinkManager(nullptr) )
, m_rDoc( i_rSwdoc )
{
}
bool DocumentLinksAdministrationManager::IsVisibleLinks() const
{
return mbVisibleLinks;
}
void DocumentLinksAdministrationManager::SetVisibleLinks(bool bFlag)
{
mbVisibleLinks = bFlag;
}
sfx2::LinkManager& DocumentLinksAdministrationManager::GetLinkManager()
{
return *m_pLinkMgr;
}
const sfx2::LinkManager& DocumentLinksAdministrationManager::GetLinkManager() const
{
return *m_pLinkMgr;
}
// #i42634# Moved common code of SwReader::Read() and SwDocShell::UpdateLinks()
// to new SwDoc::UpdateLinks():
void DocumentLinksAdministrationManager::UpdateLinks()
{
if (!m_rDoc.GetDocShell())
return;
SfxObjectCreateMode eMode = m_rDoc.GetDocShell()->GetCreateMode();
if (eMode == SfxObjectCreateMode::INTERNAL)
return;
if (eMode == SfxObjectCreateMode::ORGANIZER)
return;
if (m_rDoc.GetDocShell()->IsPreview())
return;
if (GetLinkManager().GetLinks().empty())
return;
sal_uInt16 nLinkMode = m_rDoc.GetDocumentSettingManager().getLinkUpdateMode(true);
sal_uInt16 nUpdateDocMode = m_rDoc.GetDocShell()->GetUpdateDocMode();
if (nLinkMode == NEVER && nUpdateDocMode != document::UpdateDocMode::FULL_UPDATE)
return;
bool bAskUpdate = nLinkMode == MANUAL;
bool bUpdate = true;
switch(nUpdateDocMode)
{
case document::UpdateDocMode::NO_UPDATE: bUpdate = false;break;
case document::UpdateDocMode::QUIET_UPDATE:bAskUpdate = false; break;
case document::UpdateDocMode::FULL_UPDATE: bAskUpdate = true; break;
}
if (nLinkMode == AUTOMATIC && !bAskUpdate)
{
SfxMedium * medium = m_rDoc.GetDocShell()->GetMedium();
if (!SvtSecurityOptions().isTrustedLocationUriForUpdatingLinks(
medium == nullptr ? OUString() : medium->GetName()))
{
bAskUpdate = true;
}
}
comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = m_rDoc.GetDocShell()->getEmbeddedObjectContainer();
if (bUpdate)
{
rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
SfxMedium* pMedium = m_rDoc.GetDocShell()->GetMedium();
SfxFrame* pFrame = pMedium ? pMedium->GetLoadTargetFrame() : nullptr;
weld::Window* pDlgParent = pFrame ? pFrame->GetWindow().GetFrameWeld() : nullptr;
GetLinkManager().UpdateAllLinks( bAskUpdate, false, pDlgParent );
}
else
{
rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
}
}
bool DocumentLinksAdministrationManager::GetData( const OUString& rItem, const OUString& rMimeType,
uno::Any & rValue ) const
{
// search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
bool bCaseSensitive = true;
while( true )
{
::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
if(pBkmk)
return SwServerObject(*pBkmk).GetData(rValue, rMimeType);
// Do we already have the Item?
OUString sItem( bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem));
FindItem aPara( sItem );
for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
{
if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
break;
}
if( aPara.pSectNd )
{
// found, so get the data
return SwServerObject( *aPara.pSectNd ).GetData( rValue, rMimeType );
}
if( !bCaseSensitive )
break;
bCaseSensitive = false;
}
FindItem aPara( GetAppCharClass().lowercase( rItem ));
for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
{
if (!(lcl_FindTable(pFormat, &aPara)))
break;
}
if( aPara.pTableNd )
{
return SwServerObject( *aPara.pTableNd ).GetData( rValue, rMimeType );
}
return false;
}
bool DocumentLinksAdministrationManager::SetData( const OUString& rItem, const OUString& ,
const uno::Any & )
{
// search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
bool bCaseSensitive = true;
while( true )
{
::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
if(pBkmk)
{
return false;
}
// Do we already have the Item?
OUString sItem( bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem));
FindItem aPara( sItem );
for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
{
if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
break;
}
if( aPara.pSectNd )
{
// found, so get the data
return false;
}
if( !bCaseSensitive )
break;
bCaseSensitive = false;
}
OUString sItem(GetAppCharClass().lowercase(rItem));
FindItem aPara( sItem );
for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
{
if (!(lcl_FindTable(pFormat, &aPara)))
break;
}
return false;
}
::sfx2::SvLinkSource* DocumentLinksAdministrationManager::CreateLinkSource(const OUString& rItem)
{
SwServerObject* pObj = nullptr;
// search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
bool bCaseSensitive = true;
while( true )
{
// bookmarks
::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
if(pBkmk && pBkmk->IsExpanded()
&& (nullptr == (pObj = pBkmk->GetRefObject())))
{
// mark found, but no link yet -> create hotlink
pObj = new SwServerObject(*pBkmk);
pBkmk->SetRefObject(pObj);
GetLinkManager().InsertServer(pObj);
}
if(pObj)
return pObj;
FindItem aPara(bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem));
// sections
for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
{
if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
break;
}
if(aPara.pSectNd
&& (nullptr == (pObj = aPara.pSectNd->GetSection().GetObject())))
{
// section found, but no link yet -> create hotlink
pObj = new SwServerObject( *aPara.pSectNd );
aPara.pSectNd->GetSection().SetRefObject( pObj );
GetLinkManager().InsertServer(pObj);
}
if(pObj)
return pObj;
if( !bCaseSensitive )
break;
bCaseSensitive = false;
}
FindItem aPara( GetAppCharClass().lowercase(rItem) );
// tables
for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
{
if (!(lcl_FindTable(pFormat, &aPara)))
break;
}
if(aPara.pTableNd
&& (nullptr == (pObj = aPara.pTableNd->GetTable().GetObject())))
{
// table found, but no link yet -> create hotlink
pObj = new SwServerObject(*aPara.pTableNd);
aPara.pTableNd->GetTable().SetRefObject(pObj);
GetLinkManager().InsertServer(pObj);
}
return pObj;
}
/// embedded all local links (Areas/Graphics)
bool DocumentLinksAdministrationManager::EmbedAllLinks()
{
bool bRet = false;
sfx2::LinkManager& rLnkMgr = GetLinkManager();
const ::sfx2::SvBaseLinks& rLinks = rLnkMgr.GetLinks();
if( !rLinks.empty() )
{
::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
::sfx2::SvBaseLink* pLnk = nullptr;
while( nullptr != (pLnk = lcl_FindNextRemovableLink( rLinks ) ) )
{
tools::SvRef<sfx2::SvBaseLink> xLink = pLnk;
// Tell the link that it's being destroyed!
xLink->Closed();
// if one forgot to remove itself
if( xLink.is() )
rLnkMgr.Remove( xLink.get() );
bRet = true;
}
m_rDoc.GetIDocumentUndoRedo().DelAllUndoObj();
m_rDoc.getIDocumentState().SetModified();
}
return bRet;
}
void DocumentLinksAdministrationManager::SetLinksUpdated(const bool bNewLinksUpdated)
{
mbLinksUpdated = bNewLinksUpdated;
}
bool DocumentLinksAdministrationManager::LinksUpdated() const
{
return mbLinksUpdated;
}
DocumentLinksAdministrationManager::~DocumentLinksAdministrationManager()
{
}
bool DocumentLinksAdministrationManager::SelectServerObj( const OUString& rStr, SwPaM*& rpPam, SwNodeRange*& rpRange ) const
{
// Do we actually have the Item?
rpPam = nullptr;
rpRange = nullptr;
OUString sItem( INetURLObject::decode( rStr,
INetURLObject::DecodeMechanism::WithCharset ));
sal_Int32 nPos = sItem.indexOf( cMarkSeparator );
const CharClass& rCC = GetAppCharClass();
// Extension for sections: not only link bookmarks/sections
// but also frames (text!), tables, outlines:
if( -1 != nPos )
{
bool bContinue = false;
OUString sName( sItem.copy( 0, nPos ) );
OUString sCmp( sItem.copy( nPos + 1 ));
sItem = rCC.lowercase( sItem );
FindItem aPara( sName );
if( sCmp == "table" )
{
sName = rCC.lowercase( sName );
for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
{
if (!(lcl_FindTable(pFormat, &aPara)))
break;
}
if( aPara.pTableNd )
{
rpRange = new SwNodeRange( *aPara.pTableNd, 0,
*aPara.pTableNd->EndOfSectionNode(), 1 );
return true;
}
}
else if( sCmp == "frame" )
{
SwNodeIndex* pIdx;
SwNode* pNd;
const SwFlyFrameFormat* pFlyFormat = m_rDoc.FindFlyByName( sName );
if( pFlyFormat &&
nullptr != ( pIdx = const_cast<SwNodeIndex*>(pFlyFormat->GetContent().GetContentIdx()) ) &&
!( pNd = &pIdx->GetNode())->IsNoTextNode() )
{
rpRange = new SwNodeRange( *pNd, 1, *pNd->EndOfSectionNode() );
return true;
}
}
else if( sCmp == "region" )
{
sItem = sName; // Is being dealt with further down!
bContinue = true;
}
else if( sCmp == "outline" )
{
SwPosition aPos( SwNodeIndex( m_rDoc.GetNodes() ));
if( m_rDoc.GotoOutline( aPos, sName ))
{
SwNode* pNd = &aPos.nNode.GetNode();
const int nLvl = pNd->GetTextNode()->GetAttrOutlineLevel()-1;
const SwOutlineNodes& rOutlNds = m_rDoc.GetNodes().GetOutLineNds();
SwOutlineNodes::size_type nTmpPos;
(void)rOutlNds.Seek_Entry( pNd, &nTmpPos );
rpRange = new SwNodeRange( aPos.nNode, 0, aPos.nNode );
// look for the section's end, now
for( ++nTmpPos;
nTmpPos < rOutlNds.size() &&
nLvl < rOutlNds[ nTmpPos ]->GetTextNode()->
GetAttrOutlineLevel()-1;
++nTmpPos )
; // there is no block
if( nTmpPos < rOutlNds.size() )
rpRange->aEnd = *rOutlNds[ nTmpPos ];
else
rpRange->aEnd = m_rDoc.GetNodes().GetEndOfContent();
return true;
}
}
if( !bContinue )
return false;
}
// search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
bool bCaseSensitive = true;
while( true )
{
::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), sItem, bCaseSensitive);
if(pBkmk)
{
if(pBkmk->IsExpanded())
rpPam = new SwPaM(
pBkmk->GetMarkPos(),
pBkmk->GetOtherMarkPos());
return static_cast<bool>(rpPam);
}
FindItem aPara( bCaseSensitive ? sItem : rCC.lowercase( sItem ) );
if( !m_rDoc.GetSections().empty() )
{
for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
{
if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
break;
}
if( aPara.pSectNd )
{
rpRange = new SwNodeRange( *aPara.pSectNd, 1,
*aPara.pSectNd->EndOfSectionNode() );
return true;
}
}
if( !bCaseSensitive )
break;
bCaseSensitive = false;
}
return false;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V560 A part of conditional expression is always true: pLnk.