android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / DocumentLinksAdministrationManager.cxx
blob2d491021c3a377c28d31295277a29f8e2643c7d9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <DocumentLinksAdministrationManager.hxx>
22 #include <doc.hxx>
23 #include <DocumentSettingManager.hxx>
24 #include <IDocumentUndoRedo.hxx>
25 #include <IDocumentState.hxx>
26 #include <IDocumentMarkAccess.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/linkmgr.hxx>
29 #include <sfx2/docfile.hxx>
30 #include <dialoghelp.hxx>
31 #include <linkenum.hxx>
32 #include <com/sun/star/document/UpdateDocMode.hpp>
33 #include <swtypes.hxx>
34 #include <docsh.hxx>
35 #include <bookmark.hxx>
36 #include <swserv.hxx>
37 #include <swbaslnk.hxx>
38 #include <section.hxx>
39 #include <docary.hxx>
40 #include <frmfmt.hxx>
41 #include <fmtcntnt.hxx>
42 #include <swtable.hxx>
43 #include <ndtxt.hxx>
44 #include <frameformats.hxx>
45 #include <tools/urlobj.hxx>
46 #include <unotools/charclass.hxx>
47 #include <unotools/securityoptions.hxx>
48 #include <utility>
50 using namespace ::com::sun::star;
52 //Helper functions for this file
53 namespace
55 ::sfx2::SvBaseLink* lcl_FindNextRemovableLink( const ::sfx2::SvBaseLinks& rLinks )
57 for (const auto& rLinkIter : rLinks)
59 ::sfx2::SvBaseLink& rLnk = *rLinkIter;
60 if ((sfx2::SvBaseLinkObjectType::ClientGraphic == rLnk.GetObjType() || sfx2::SvBaseLinkObjectType::ClientFile == rLnk.GetObjType())
61 && dynamic_cast<const SwBaseLink*>(&rLnk) != nullptr)
63 tools::SvRef<sfx2::SvBaseLink> xLink(&rLnk);
65 OUString sFName;
66 sfx2::LinkManager::GetDisplayNames( xLink.get(), nullptr, &sFName );
68 INetURLObject aURL( sFName );
69 if( INetProtocol::File == aURL.GetProtocol() ||
70 INetProtocol::Cid == aURL.GetProtocol() )
71 return &rLnk;
74 return nullptr;
78 ::sw::mark::DdeBookmark* lcl_FindDdeBookmark( const IDocumentMarkAccess& rMarkAccess, const OUString& rName, const bool bCaseSensitive )
80 //Iterating over all bookmarks, checking DdeBookmarks
81 const OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lowercase(rName);
82 for(IDocumentMarkAccess::const_iterator_t ppMark = rMarkAccess.getAllMarksBegin();
83 ppMark != rMarkAccess.getAllMarksEnd();
84 ++ppMark)
86 if (::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(*ppMark))
88 if (
89 (bCaseSensitive && (pBkmk->GetName() == sNameLc)) ||
90 (!bCaseSensitive && GetAppCharClass().lowercase(pBkmk->GetName()) == sNameLc)
93 return pBkmk;
97 return nullptr;
101 SwSectionNode* lcl_FindSection(const SwDoc& rDoc, const OUString& rItem, bool bCaseSensitive)
103 const OUString sCompare = bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem);
104 for (const SwSectionFormat* pSectFormat : rDoc.GetSections())
106 SwSection* pSect = pSectFormat->GetSection();
107 if (pSect)
109 OUString sNm(bCaseSensitive ? pSect->GetSectionName()
110 : GetAppCharClass().lowercase(pSect->GetSectionName()));
111 if (sNm == sCompare)
113 // found, so get the data
114 const SwNodeIndex* pIdx = pSectFormat->GetContent().GetContentIdx();
115 if (pIdx && &pSectFormat->GetDoc()->GetNodes() == &pIdx->GetNodes())
117 // a table in the normal NodesArr
118 return pIdx->GetNode().GetSectionNode();
120 // If the name is already correct, but not the rest then we don't have them.
121 // The names are always unique.
125 return nullptr;
128 SwTableNode* lcl_FindTable(const SwDoc& rDoc, const OUString& rItem)
130 const OUString& aItem = GetAppCharClass().lowercase(rItem);
131 for (const SwFrameFormat* pTableFormat : *rDoc.GetTableFrameFormats())
133 OUString sNm(GetAppCharClass().lowercase(pTableFormat->GetName()));
134 if (sNm == aItem)
136 SwTable* pTmpTable = SwTable::FindTable(pTableFormat);
137 if (pTmpTable)
139 SwTableBox* pFBox = pTmpTable->GetTabSortBoxes()[0];
140 if (pFBox && pFBox->GetSttNd()
141 && &pTableFormat->GetDoc()->GetNodes() == &pFBox->GetSttNd()->GetNodes())
143 // a table in the normal NodesArr
144 return const_cast<SwTableNode*>(pFBox->GetSttNd()->FindTableNode());
147 // If the name is already correct, but not the rest then we don't have them.
148 // The names are always unique.
151 return nullptr;
157 namespace sw
160 DocumentLinksAdministrationManager::DocumentLinksAdministrationManager( SwDoc& i_rSwdoc )
161 : mbVisibleLinks(true)
162 , mbLinksUpdated( false ) //#i38810#
163 , m_pLinkMgr( new sfx2::LinkManager(nullptr) )
164 , m_rDoc( i_rSwdoc )
168 bool DocumentLinksAdministrationManager::IsVisibleLinks() const
170 return mbVisibleLinks;
173 void DocumentLinksAdministrationManager::SetVisibleLinks(bool bFlag)
175 mbVisibleLinks = bFlag;
178 sfx2::LinkManager& DocumentLinksAdministrationManager::GetLinkManager()
180 return *m_pLinkMgr;
183 const sfx2::LinkManager& DocumentLinksAdministrationManager::GetLinkManager() const
185 return *m_pLinkMgr;
188 // #i42634# Moved common code of SwReader::Read() and SwDocShell::UpdateLinks()
189 // to new SwDoc::UpdateLinks():
190 void DocumentLinksAdministrationManager::UpdateLinks()
192 if (!m_rDoc.GetDocShell())
193 return;
194 SfxObjectCreateMode eMode = m_rDoc.GetDocShell()->GetCreateMode();
195 if (eMode == SfxObjectCreateMode::INTERNAL)
196 return;
197 if (eMode == SfxObjectCreateMode::ORGANIZER)
198 return;
199 if (m_rDoc.GetDocShell()->IsPreview())
200 return;
201 if (GetLinkManager().GetLinks().empty())
202 return;
203 sal_uInt16 nLinkMode = m_rDoc.GetDocumentSettingManager().getLinkUpdateMode(true);
204 sal_uInt16 nUpdateDocMode = m_rDoc.GetDocShell()->GetUpdateDocMode();
205 if (nLinkMode == NEVER && nUpdateDocMode != document::UpdateDocMode::FULL_UPDATE)
206 return;
208 bool bAskUpdate = nLinkMode == MANUAL;
209 bool bUpdate = true;
210 switch(nUpdateDocMode)
212 case document::UpdateDocMode::NO_UPDATE: bUpdate = false;break;
213 case document::UpdateDocMode::QUIET_UPDATE:bAskUpdate = false; break;
214 case document::UpdateDocMode::FULL_UPDATE: bAskUpdate = true; break;
216 if (nLinkMode == AUTOMATIC && !bAskUpdate)
218 SfxMedium * medium = m_rDoc.GetDocShell()->GetMedium();
219 if (!SvtSecurityOptions::isTrustedLocationUriForUpdatingLinks(
220 medium == nullptr ? OUString() : medium->GetName()))
222 bAskUpdate = true;
225 comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = m_rDoc.GetDocShell()->getEmbeddedObjectContainer();
226 if (bUpdate)
228 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
230 weld::Window* pDlgParent = GetFrameWeld(m_rDoc.GetDocShell());
231 GetLinkManager().UpdateAllLinks(bAskUpdate, false, pDlgParent);
233 else
235 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
239 bool DocumentLinksAdministrationManager::GetData( const OUString& rItem, const OUString& rMimeType,
240 uno::Any & rValue ) const
242 // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
243 bool bCaseSensitive = true;
244 while( true )
246 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
247 if(pBkmk)
248 return SwServerObject(*pBkmk).GetData(rValue, rMimeType);
250 // Do we already have the Item?
251 if (SwSectionNode* pSectNd = lcl_FindSection(m_rDoc, rItem, bCaseSensitive))
253 // found, so get the data
254 return SwServerObject(*pSectNd).GetData( rValue, rMimeType );
256 if( !bCaseSensitive )
257 break;
258 bCaseSensitive = false;
261 if (SwTableNode* pTableNd = lcl_FindTable(m_rDoc, rItem))
263 return SwServerObject(*pTableNd).GetData( rValue, rMimeType );
266 return false;
269 // TODO/FIXME: do something with the found items? For now, it's just an expensive no-op.
270 void DocumentLinksAdministrationManager::SetData( const OUString& rItem )
272 // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
273 bool bCaseSensitive = true;
274 while( true )
276 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
277 if(pBkmk)
279 return;
282 // Do we already have the Item?
283 if (lcl_FindSection(m_rDoc, rItem, bCaseSensitive))
285 // found, so get the data
286 return;
288 if( !bCaseSensitive )
289 break;
290 bCaseSensitive = false;
293 (void)lcl_FindTable(m_rDoc, rItem);
296 ::sfx2::SvLinkSource* DocumentLinksAdministrationManager::CreateLinkSource(const OUString& rItem)
298 // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
299 bool bCaseSensitive = true;
300 while( true )
302 // bookmarks
303 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
304 if(pBkmk && pBkmk->IsExpanded())
306 SwServerObject* pObj = pBkmk->GetRefObject();
307 if( !pObj )
309 // mark found, but no link yet -> create hotlink
310 pObj = new SwServerObject(*pBkmk);
311 pBkmk->SetRefObject(pObj);
312 GetLinkManager().InsertServer(pObj);
314 return pObj;
317 // sections
318 if (SwSectionNode* pSectNd = lcl_FindSection(m_rDoc, rItem, bCaseSensitive))
320 SwServerObject* pObj = pSectNd->GetSection().GetObject();
321 if( !pObj )
323 // section found, but no link yet -> create hotlink
324 pObj = new SwServerObject(*pSectNd);
325 pSectNd->GetSection().SetRefObject( pObj );
326 GetLinkManager().InsertServer(pObj);
328 return pObj;
330 if( !bCaseSensitive )
331 break;
332 bCaseSensitive = false;
335 // tables
336 if (SwTableNode* pTableNd = lcl_FindTable(m_rDoc, rItem))
338 SwServerObject* pObj = pTableNd->GetTable().GetObject();
339 if( !pObj )
341 // table found, but no link yet -> create hotlink
342 pObj = new SwServerObject(*pTableNd);
343 pTableNd->GetTable().SetRefObject(pObj);
344 GetLinkManager().InsertServer(pObj);
346 return pObj;
348 return nullptr;
351 /// embedded all local links (Areas/Graphics)
352 bool DocumentLinksAdministrationManager::EmbedAllLinks()
354 bool bRet = false;
355 sfx2::LinkManager& rLnkMgr = GetLinkManager();
356 const ::sfx2::SvBaseLinks& rLinks = rLnkMgr.GetLinks();
357 if( !rLinks.empty() )
359 ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
361 ::sfx2::SvBaseLink* pLnk = nullptr;
362 while( nullptr != (pLnk = lcl_FindNextRemovableLink( rLinks ) ) )
364 tools::SvRef<sfx2::SvBaseLink> xLink = pLnk;
365 // Tell the link that it's being destroyed!
366 xLink->Closed();
368 // if one forgot to remove itself
369 if( xLink.is() )
370 rLnkMgr.Remove( xLink.get() );
372 bRet = true;
375 m_rDoc.GetIDocumentUndoRedo().DelAllUndoObj();
376 m_rDoc.getIDocumentState().SetModified();
378 return bRet;
381 void DocumentLinksAdministrationManager::SetLinksUpdated(const bool bNewLinksUpdated)
383 mbLinksUpdated = bNewLinksUpdated;
386 bool DocumentLinksAdministrationManager::LinksUpdated() const
388 return mbLinksUpdated;
391 DocumentLinksAdministrationManager::~DocumentLinksAdministrationManager()
395 bool DocumentLinksAdministrationManager::SelectServerObj( std::u16string_view rStr, SwPaM*& rpPam, std::optional<SwNodeRange>& roRange ) const
397 // Do we actually have the Item?
398 rpPam = nullptr;
399 roRange.reset();
401 OUString sItem( INetURLObject::decode( rStr,
402 INetURLObject::DecodeMechanism::WithCharset ));
404 sal_Int32 nPos = sItem.indexOf( cMarkSeparator );
406 // Extension for sections: not only link bookmarks/sections
407 // but also frames (text!), tables, outlines:
408 if( -1 != nPos )
410 OUString sName( sItem.copy( 0, nPos ) );
411 std::u16string_view sCmp( sItem.subView( nPos + 1 ));
413 if( sCmp == u"table" )
415 if (SwTableNode* pTableNd = lcl_FindTable(m_rDoc, sName))
417 roRange.emplace( *pTableNd, SwNodeOffset(0),
418 *pTableNd->EndOfSectionNode(), SwNodeOffset(1) );
420 return roRange.has_value();
422 else if( sCmp == u"frame" )
424 const SwFlyFrameFormat* pFlyFormat = m_rDoc.FindFlyByName( sName );
425 if( pFlyFormat )
427 SwNodeIndex* pIdx = const_cast<SwNodeIndex*>(pFlyFormat->GetContent().GetContentIdx());
428 if( pIdx )
430 SwNode* pNd = &pIdx->GetNode();
431 if( !pNd->IsNoTextNode() )
433 roRange.emplace( *pNd, SwNodeOffset(1), *pNd->EndOfSectionNode() );
437 return roRange.has_value();
439 else if( sCmp == u"region" )
441 sItem = sName; // Is being dealt with further down!
443 else if( sCmp == u"outline" )
445 SwPosition aPos( m_rDoc.GetNodes() );
446 if (m_rDoc.GotoOutline(aPos, sName, nullptr))
448 SwNode* pNd = &aPos.GetNode();
449 const int nLvl = pNd->GetTextNode()->GetAttrOutlineLevel()-1;
451 const SwOutlineNodes& rOutlNds = m_rDoc.GetNodes().GetOutLineNds();
452 SwOutlineNodes::size_type nTmpPos;
453 (void)rOutlNds.Seek_Entry( pNd, &nTmpPos );
454 roRange.emplace( aPos.GetNode(), SwNodeOffset(0), aPos.GetNode() );
456 // look for the section's end, now
457 for( ++nTmpPos;
458 nTmpPos < rOutlNds.size() &&
459 nLvl < rOutlNds[ nTmpPos ]->GetTextNode()->
460 GetAttrOutlineLevel()-1;
461 ++nTmpPos )
462 ; // there is no block
464 if( nTmpPos < rOutlNds.size() )
465 roRange->aEnd = *rOutlNds[ nTmpPos ];
466 else
467 roRange->aEnd = m_rDoc.GetNodes().GetEndOfContent();
469 return roRange.has_value();
473 // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
474 bool bCaseSensitive = true;
475 while( true )
477 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), sItem, bCaseSensitive);
478 if(pBkmk)
480 if(pBkmk->IsExpanded())
481 rpPam = new SwPaM(
482 pBkmk->GetMarkPos(),
483 pBkmk->GetOtherMarkPos());
484 return static_cast<bool>(rpPam);
487 if( !m_rDoc.GetSections().empty() )
489 if (SwSectionNode* pSectNd = lcl_FindSection(m_rDoc, sItem, bCaseSensitive))
491 roRange.emplace( *pSectNd, SwNodeOffset(1),
492 *pSectNd->EndOfSectionNode() );
493 return true;
497 if( !bCaseSensitive )
498 break;
499 bCaseSensitive = false;
501 return false;
508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */