LibreOffice Module sw (master) 1
DocumentLinksAdministrationManager.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21
22#include <doc.hxx>
24#include <IDocumentUndoRedo.hxx>
25#include <IDocumentState.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>
48#include <utility>
49
50using namespace ::com::sun::star;
51
52//Helper functions for this file
53namespace
54{
55 ::sfx2::SvBaseLink* lcl_FindNextRemovableLink( const ::sfx2::SvBaseLinks& rLinks )
56 {
57 for (const auto& rLinkIter : rLinks)
58 {
59 ::sfx2::SvBaseLink& rLnk = *rLinkIter;
61 && dynamic_cast<const SwBaseLink*>(&rLnk) != nullptr)
62 {
64
65 OUString sFName;
66 sfx2::LinkManager::GetDisplayNames( xLink.get(), nullptr, &sFName );
67
68 INetURLObject aURL( sFName );
69 if( INetProtocol::File == aURL.GetProtocol() ||
70 INetProtocol::Cid == aURL.GetProtocol() )
71 return &rLnk;
72 }
73 }
74 return nullptr;
75 }
76
77
78 ::sw::mark::DdeBookmark* lcl_FindDdeBookmark( const IDocumentMarkAccess& rMarkAccess, const OUString& rName, const bool bCaseSensitive )
79 {
80 //Iterating over all bookmarks, checking DdeBookmarks
81 const OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lowercase(rName);
83 ppMark != rMarkAccess.getAllMarksEnd();
84 ++ppMark)
85 {
86 if (::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(*ppMark))
87 {
88 if (
89 (bCaseSensitive && (pBkmk->GetName() == sNameLc)) ||
90 (!bCaseSensitive && GetAppCharClass().lowercase(pBkmk->GetName()) == sNameLc)
91 )
92 {
93 return pBkmk;
94 }
95 }
96 }
97 return nullptr;
98 }
99
100
101 SwSectionNode* lcl_FindSection(const SwDoc& rDoc, const OUString& rItem, bool bCaseSensitive)
102 {
103 const OUString sCompare = bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem);
104 for (const SwSectionFormat* pSectFormat : rDoc.GetSections())
105 {
106 SwSection* pSect = pSectFormat->GetSection();
107 if (pSect)
108 {
109 OUString sNm(bCaseSensitive ? pSect->GetSectionName()
110 : GetAppCharClass().lowercase(pSect->GetSectionName()));
111 if (sNm == sCompare)
112 {
113 // found, so get the data
114 const SwNodeIndex* pIdx = pSectFormat->GetContent().GetContentIdx();
115 if (pIdx && &pSectFormat->GetDoc()->GetNodes() == &pIdx->GetNodes())
116 {
117 // a table in the normal NodesArr
118 return pIdx->GetNode().GetSectionNode();
119 }
120 // If the name is already correct, but not the rest then we don't have them.
121 // The names are always unique.
122 }
123 }
124 }
125 return nullptr;
126 }
127
128 SwTableNode* lcl_FindTable(const SwDoc& rDoc, const OUString& rItem)
129 {
130 const OUString& aItem = GetAppCharClass().lowercase(rItem);
131 for (const SwFrameFormat* pTableFormat : *rDoc.GetTableFrameFormats())
132 {
133 OUString sNm(GetAppCharClass().lowercase(pTableFormat->GetName()));
134 if (sNm == aItem)
135 {
136 SwTable* pTmpTable = SwTable::FindTable(pTableFormat);
137 if (pTmpTable)
138 {
139 SwTableBox* pFBox = pTmpTable->GetTabSortBoxes()[0];
140 if (pFBox && pFBox->GetSttNd()
141 && &pTableFormat->GetDoc()->GetNodes() == &pFBox->GetSttNd()->GetNodes())
142 {
143 // a table in the normal NodesArr
144 return const_cast<SwTableNode*>(pFBox->GetSttNd()->FindTableNode());
145 }
146 }
147 // If the name is already correct, but not the rest then we don't have them.
148 // The names are always unique.
149 }
150 }
151 return nullptr;
152 }
153
154}
155
156
157namespace sw
158{
159
161 : mbVisibleLinks(true)
162 , mbLinksUpdated( false ) //#i38810#
163 , m_pLinkMgr( new sfx2::LinkManager(nullptr) )
164 , m_rDoc( i_rSwdoc )
165{
166}
167
169{
170 return mbVisibleLinks;
171}
172
174{
175 mbVisibleLinks = bFlag;
176}
177
179{
180 return *m_pLinkMgr;
181}
182
184{
185 return *m_pLinkMgr;
186}
187
188// #i42634# Moved common code of SwReader::Read() and SwDocShell::UpdateLinks()
189// to new SwDoc::UpdateLinks():
191{
192 if (!m_rDoc.GetDocShell())
193 return;
195 if (eMode == SfxObjectCreateMode::INTERNAL)
196 return;
197 if (eMode == SfxObjectCreateMode::ORGANIZER)
198 return;
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;
207
208 bool bAskUpdate = nLinkMode == MANUAL;
209 bool bUpdate = true;
210 switch(nUpdateDocMode)
211 {
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;
215 }
216 if (nLinkMode == AUTOMATIC && !bAskUpdate)
217 {
220 medium == nullptr ? OUString() : medium->GetName()))
221 {
222 bAskUpdate = true;
223 }
224 }
226 if (bUpdate)
227 {
228 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
229
231 GetLinkManager().UpdateAllLinks(bAskUpdate, false, pDlgParent);
232 }
233 else
234 {
235 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false);
236 }
237}
238
239bool DocumentLinksAdministrationManager::GetData( const OUString& rItem, const OUString& rMimeType,
240 uno::Any & rValue ) const
241{
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 )
245 {
246 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
247 if(pBkmk)
248 return SwServerObject(*pBkmk).GetData(rValue, rMimeType);
249
250 // Do we already have the Item?
251 if (SwSectionNode* pSectNd = lcl_FindSection(m_rDoc, rItem, bCaseSensitive))
252 {
253 // found, so get the data
254 return SwServerObject(*pSectNd).GetData( rValue, rMimeType );
255 }
256 if( !bCaseSensitive )
257 break;
258 bCaseSensitive = false;
259 }
260
261 if (SwTableNode* pTableNd = lcl_FindTable(m_rDoc, rItem))
262 {
263 return SwServerObject(*pTableNd).GetData( rValue, rMimeType );
264 }
265
266 return false;
267}
268
269// TODO/FIXME: do something with the found items? For now, it's just an expensive no-op.
271{
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 )
275 {
276 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
277 if(pBkmk)
278 {
279 return;
280 }
281
282 // Do we already have the Item?
283 if (lcl_FindSection(m_rDoc, rItem, bCaseSensitive))
284 {
285 // found, so get the data
286 return;
287 }
288 if( !bCaseSensitive )
289 break;
290 bCaseSensitive = false;
291 }
292
293 (void)lcl_FindTable(m_rDoc, rItem);
294}
295
297{
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 )
301 {
302 // bookmarks
303 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
304 if(pBkmk && pBkmk->IsExpanded())
305 {
306 SwServerObject* pObj = pBkmk->GetRefObject();
307 if( !pObj )
308 {
309 // mark found, but no link yet -> create hotlink
310 pObj = new SwServerObject(*pBkmk);
311 pBkmk->SetRefObject(pObj);
313 }
314 return pObj;
315 }
316
317 // sections
318 if (SwSectionNode* pSectNd = lcl_FindSection(m_rDoc, rItem, bCaseSensitive))
319 {
320 SwServerObject* pObj = pSectNd->GetSection().GetObject();
321 if( !pObj )
322 {
323 // section found, but no link yet -> create hotlink
324 pObj = new SwServerObject(*pSectNd);
325 pSectNd->GetSection().SetRefObject( pObj );
327 }
328 return pObj;
329 }
330 if( !bCaseSensitive )
331 break;
332 bCaseSensitive = false;
333 }
334
335 // tables
336 if (SwTableNode* pTableNd = lcl_FindTable(m_rDoc, rItem))
337 {
338 SwServerObject* pObj = pTableNd->GetTable().GetObject();
339 if( !pObj )
340 {
341 // table found, but no link yet -> create hotlink
342 pObj = new SwServerObject(*pTableNd);
343 pTableNd->GetTable().SetRefObject(pObj);
345 }
346 return pObj;
347 }
348 return nullptr;
349}
350
353{
354 bool bRet = false;
356 const ::sfx2::SvBaseLinks& rLinks = rLnkMgr.GetLinks();
357 if( !rLinks.empty() )
358 {
360
361 ::sfx2::SvBaseLink* pLnk = nullptr;
362 while( nullptr != (pLnk = lcl_FindNextRemovableLink( rLinks ) ) )
363 {
365 // Tell the link that it's being destroyed!
366 xLink->Closed();
367
368 // if one forgot to remove itself
369 if( xLink.is() )
370 rLnkMgr.Remove( xLink.get() );
371
372 bRet = true;
373 }
374
375 m_rDoc.GetIDocumentUndoRedo().DelAllUndoObj();
377 }
378 return bRet;
379}
380
382{
383 mbLinksUpdated = bNewLinksUpdated;
384}
385
387{
388 return mbLinksUpdated;
389}
390
392{
393}
394
395bool DocumentLinksAdministrationManager::SelectServerObj( std::u16string_view rStr, SwPaM*& rpPam, std::optional<SwNodeRange>& roRange ) const
396{
397 // Do we actually have the Item?
398 rpPam = nullptr;
399 roRange.reset();
400
401 OUString sItem( INetURLObject::decode( rStr,
403
404 sal_Int32 nPos = sItem.indexOf( cMarkSeparator );
405
406 // Extension for sections: not only link bookmarks/sections
407 // but also frames (text!), tables, outlines:
408 if( -1 != nPos )
409 {
410 OUString sName( sItem.copy( 0, nPos ) );
411 std::u16string_view sCmp( sItem.subView( nPos + 1 ));
412
413 if( sCmp == u"table" )
414 {
415 if (SwTableNode* pTableNd = lcl_FindTable(m_rDoc, sName))
416 {
417 roRange.emplace( *pTableNd, SwNodeOffset(0),
418 *pTableNd->EndOfSectionNode(), SwNodeOffset(1) );
419 }
420 return roRange.has_value();
421 }
422 else if( sCmp == u"frame" )
423 {
424 const SwFlyFrameFormat* pFlyFormat = m_rDoc.FindFlyByName( sName );
425 if( pFlyFormat )
426 {
427 SwNodeIndex* pIdx = const_cast<SwNodeIndex*>(pFlyFormat->GetContent().GetContentIdx());
428 if( pIdx )
429 {
430 SwNode* pNd = &pIdx->GetNode();
431 if( !pNd->IsNoTextNode() )
432 {
433 roRange.emplace( *pNd, SwNodeOffset(1), *pNd->EndOfSectionNode() );
434 }
435 }
436 }
437 return roRange.has_value();
438 }
439 else if( sCmp == u"region" )
440 {
441 sItem = sName; // Is being dealt with further down!
442 }
443 else if( sCmp == u"outline" )
444 {
445 SwPosition aPos( m_rDoc.GetNodes() );
446 if (m_rDoc.GotoOutline(aPos, sName, nullptr))
447 {
448 SwNode* pNd = &aPos.GetNode();
449 const int nLvl = pNd->GetTextNode()->GetAttrOutlineLevel()-1;
450
451 const SwOutlineNodes& rOutlNds = m_rDoc.GetNodes().GetOutLineNds();
453 (void)rOutlNds.Seek_Entry( pNd, &nTmpPos );
454 roRange.emplace( aPos.GetNode(), SwNodeOffset(0), aPos.GetNode() );
455
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
463
464 if( nTmpPos < rOutlNds.size() )
465 roRange->aEnd = *rOutlNds[ nTmpPos ];
466 else
467 roRange->aEnd = m_rDoc.GetNodes().GetEndOfContent();
468 }
469 return roRange.has_value();
470 }
471 }
472
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 )
476 {
477 ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), sItem, bCaseSensitive);
478 if(pBkmk)
479 {
480 if(pBkmk->IsExpanded())
481 rpPam = new SwPaM(
482 pBkmk->GetMarkPos(),
483 pBkmk->GetOtherMarkPos());
484 return static_cast<bool>(rpPam);
485 }
486
487 if( !m_rDoc.GetSections().empty() )
488 {
489 if (SwSectionNode* pSectNd = lcl_FindSection(m_rDoc, sItem, bCaseSensitive))
490 {
491 roRange.emplace( *pSectNd, SwNodeOffset(1),
492 *pSectNd->EndOfSectionNode() );
493 return true;
494
495 }
496 }
497 if( !bCaseSensitive )
498 break;
499 bCaseSensitive = false;
500 }
501 return false;
502}
503
504
505}
506
507
508/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString lowercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
wrapper iterator: wraps iterator of implementation while hiding MarkBase class; only IMark instances ...
Provides access to the marks of a document.
virtual const_iterator_t getAllMarksEnd() const =0
returns a STL-like random access iterator to the end of the sequence of marks.
virtual const_iterator_t getAllMarksBegin() const =0
returns a STL-like random access iterator to the begin of the sequence of marks.
virtual void SetModified()=0
Must be called manually at changes of format.
static OUString decode(std::u16string_view rText, DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
SfxMedium * GetMedium() const
SfxObjectCreateMode GetCreateMode() const
virtual comphelper::EmbeddedObjectContainer & getEmbeddedObjectContainer() const override
bool IsPreview() const
sal_Int16 GetUpdateDocMode() const
Definition: docsh.hxx:288
Definition: doc.hxx:197
SwSectionFormats & GetSections()
Definition: doc.hxx:1356
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:408
const sw::TableFrameFormats * GetTableFrameFormats() const
Definition: doc.hxx:826
bool GotoOutline(SwPosition &rPos, const OUString &rName, SwRootFrame const *=nullptr) const
Definition: docnum.cxx:733
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:158
SwNodes & GetNodes()
Definition: doc.hxx:422
const SwFlyFrameFormat * FindFlyByName(const OUString &rName, SwNodeType nNdTyp=SwNodeType::NONE) const
Definition: doclay.cxx:1420
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1890
::sw::DocumentSettingManager & GetDocumentSettingManager()
Definition: doc.cxx:200
SwDocShell * GetDocShell()
Definition: doc.hxx:1370
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
const SwFormatContent & GetContent(bool=true) const
Definition: fmtcntnt.hxx:55
Style of a layout element.
Definition: frmfmt.hxx:72
Marks a node in the document model.
Definition: ndindex.hxx:31
const SwNodes & GetNodes() const
Definition: ndindex.hxx:119
SwNode & GetNode() const
Definition: ndindex.hxx:123
Base class of the Writer document model elements.
Definition: node.hxx:98
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:901
SwSectionNode * GetSectionNode()
Definition: node.hxx:658
bool IsNoTextNode() const
Definition: node.hxx:194
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:706
SwDoc & GetDoc()
Definition: node.hxx:233
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:380
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:695
const SwOutlineNodes & GetOutLineNds() const
Array of all OutlineNodes.
Definition: ndarr.hxx:236
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:165
bool Seek_Entry(SwNode *rP, size_type *pnPos) const
Definition: ndnum.cxx:32
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:188
A section node represents the start of a section on the UI, i.e.
Definition: node.hxx:575
const OUString & GetSectionName() const
Definition: section.hxx:171
virtual bool GetData(css::uno::Any &rData, const OUString &rMimeType, bool bSynchron=false) override
Definition: swserv.cxx:40
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:443
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:495
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:113
static SwTable * FindTable(SwFrameFormat const *const pFormat)
Definition: swtable.cxx:2308
SwTableSortBoxes & GetTabSortBoxes()
Definition: swtable.hxx:267
int GetAttrOutlineLevel() const
Returns outline level of this text node.
Definition: ndtxt.cxx:4168
bool empty() const
Definition: docary.hxx:86
size_type size() const
static bool GetDisplayNames(const SvBaseLink *, OUString *pType, OUString *pFile=nullptr, OUString *pLink=nullptr, OUString *pFilter=nullptr)
bool InsertServer(SvLinkSource *rObj)
void UpdateAllLinks(bool bAskUpdate, bool bUpdateGrfLinks, weld::Window *pParentWin)
void Remove(SvBaseLink const *pLink)
const SvBaseLinks & GetLinks() const
bool SelectServerObj(std::u16string_view rStr, SwPaM *&rpPam, std::optional< SwNodeRange > &rpRange) const
bool EmbedAllLinks() override
embedded all local links (Areas/Graphics)
bool IsVisibleLinks() const override
Insert links in-/visibly into LinkManager (linked ranges).
bool GetData(const OUString &rItem, const OUString &rMimeType, css::uno::Any &rValue) const override
for linking of parts of documents.
void SetLinksUpdated(const bool bNewLinksUpdated) override
::sfx2::SvLinkSource * CreateLinkSource(const OUString &rItem) override
void UpdateLinks() override
#i42634# Moved common code of SwReader::Read() and SwDocShell::UpdateLinks() to new SwDoc::UpdateLink...
virtual sal_uInt16 getLinkUpdateMode(bool bGlobalSettings) const override
Get the current link update mode.
const SwServerObject * GetRefObject() const
void SetRefObject(SwServerObject *pObj)
bool IsExpanded() const override
SwPosition & GetMarkPos() const override
SwPosition & GetOtherMarkPos() const override
T * get() const
bool is() const
weld::Window * GetFrameWeld(const SfxFrame *pFrame)
Definition: dialoghelp.cxx:19
URL aURL
SwDoc & m_rDoc
Definition: docbm.cxx:1228
float u
OUString sName
CharClass & GetAppCharClass()
Definition: init.cxx:721
Mode eMode
@ NEVER
Definition: linkenum.hxx:24
@ MANUAL
Definition: linkenum.hxx:25
sal_uInt16 nPos
bool isTrustedLocationUriForUpdatingLinks(OUString const &uri)
AUTOMATIC
Dialog to specify the properties of date form field.
o3tl::strong_int< sal_Int32, struct Tag_SwNodeOffset > SwNodeOffset
Definition: nodeoffset.hxx:16
SfxObjectCreateMode
Marks a position in the document model.
Definition: pam.hxx:38
SwNode & GetNode() const
Definition: pam.hxx:81
const sal_Unicode cMarkSeparator
Definition: swtypes.hxx:124