Line data Source code
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 :
20 : #include <DocumentLinksAdministrationManager.hxx>
21 :
22 : #include <doc.hxx>
23 : #include <DocumentSettingManager.hxx>
24 : #include <IDocumentUndoRedo.hxx>
25 : #include <IDocumentState.hxx>
26 : #include <IDocumentLayoutAccess.hxx>
27 : #include <sfx2/objsh.hxx>
28 : #include <sfx2/linkmgr.hxx>
29 : #include <sfx2/docfile.hxx>
30 : #include <sfx2/frame.hxx>
31 : #include <linkenum.hxx>
32 : #include <com/sun/star/document/UpdateDocMode.hpp>
33 : #include <swtypes.hxx>
34 : #include <viewsh.hxx>
35 : #include <docsh.hxx>
36 : #include <bookmrk.hxx>
37 : #include <swserv.hxx>
38 : #include <swbaslnk.hxx>
39 : #include <section.hxx>
40 : #include <docary.hxx>
41 : #include <frmfmt.hxx>
42 : #include <fmtcntnt.hxx>
43 : #include <swtable.hxx>
44 : #include <ndtxt.hxx>
45 : #include <tools/urlobj.hxx>
46 : #include <unotools/charclass.hxx>
47 :
48 : using namespace ::com::sun::star;
49 :
50 : //Helper functions for this file
51 : namespace
52 : {
53 0 : struct _FindItem
54 : {
55 : const OUString m_Item;
56 : SwTableNode* pTableNd;
57 : SwSectionNode* pSectNd;
58 :
59 0 : explicit _FindItem(const OUString& rS)
60 0 : : m_Item(rS), pTableNd(0), pSectNd(0)
61 0 : {}
62 : };
63 :
64 0 : ::sfx2::SvBaseLink* lcl_FindNextRemovableLink( const ::sfx2::SvBaseLinks& rLinks )
65 : {
66 0 : for( ::sfx2::SvBaseLinks::size_type n = 0; n < rLinks.size(); ++n )
67 : {
68 0 : ::sfx2::SvBaseLink* pLnk = &(*rLinks[ n ]);
69 0 : if( pLnk &&
70 0 : ( OBJECT_CLIENT_GRF == pLnk->GetObjType() ||
71 0 : OBJECT_CLIENT_FILE == pLnk->GetObjType() ) &&
72 0 : pLnk->ISA( SwBaseLink ) )
73 : {
74 0 : ::sfx2::SvBaseLinkRef xLink = pLnk;
75 :
76 0 : OUString sFName;
77 0 : sfx2::LinkManager::GetDisplayNames( xLink, 0, &sFName, 0, 0 );
78 :
79 0 : INetURLObject aURL( sFName );
80 0 : if( INetProtocol::File == aURL.GetProtocol() ||
81 0 : INetProtocol::Cid == aURL.GetProtocol() )
82 0 : return pLnk;
83 : }
84 : }
85 0 : return 0;
86 : }
87 :
88 :
89 1 : ::sw::mark::DdeBookmark* lcl_FindDdeBookmark( const IDocumentMarkAccess& rMarkAccess, const OUString& rName, const bool bCaseSensitive )
90 : {
91 : //Iterating over all bookmarks, checking DdeBookmarks
92 1 : const OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lowercase(rName);
93 3 : for(IDocumentMarkAccess::const_iterator_t ppMark = rMarkAccess.getAllMarksBegin();
94 2 : ppMark != rMarkAccess.getAllMarksEnd();
95 : ++ppMark)
96 : {
97 1 : if ( IDocumentMarkAccess::GetType( *(ppMark->get()) ) == IDocumentMarkAccess::MarkType::DDE_BOOKMARK)
98 : {
99 1 : ::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(ppMark->get());
100 1 : if (!pBkmk)
101 1 : return NULL;
102 3 : if (
103 2 : (bCaseSensitive && (pBkmk->GetName() == sNameLc)) ||
104 1 : (!bCaseSensitive && GetAppCharClass().lowercase(pBkmk->GetName()) == sNameLc)
105 : )
106 : {
107 1 : return pBkmk;
108 : }
109 : }
110 : }
111 1 : return NULL;
112 : }
113 :
114 :
115 0 : bool lcl_FindSection( const SwSectionFormat* pSectFormat, _FindItem * const pItem, bool bCaseSensitive )
116 : {
117 0 : SwSection* pSect = pSectFormat->GetSection();
118 0 : if( pSect )
119 : {
120 : OUString sNm( (bCaseSensitive)
121 : ? pSect->GetSectionName()
122 0 : : GetAppCharClass().lowercase( pSect->GetSectionName() ));
123 : OUString sCompare( (bCaseSensitive)
124 : ? pItem->m_Item
125 0 : : GetAppCharClass().lowercase( pItem->m_Item ) );
126 0 : if( sNm == sCompare )
127 : {
128 : // found, so get the data
129 : const SwNodeIndex* pIdx;
130 0 : if( 0 != (pIdx = pSectFormat->GetContent().GetContentIdx() ) &&
131 0 : &pSectFormat->GetDoc()->GetNodes() == &pIdx->GetNodes() )
132 : {
133 : // a table in the normal NodesArr
134 0 : pItem->pSectNd = pIdx->GetNode().GetSectionNode();
135 0 : return false;
136 : }
137 : // If the name is already correct, but not the rest then we don't have them.
138 : // The names are always unique.
139 0 : }
140 : }
141 0 : return true;
142 : }
143 :
144 0 : bool lcl_FindTable( const SwFrameFormat* pTableFormat, _FindItem * const pItem )
145 : {
146 0 : OUString sNm( GetAppCharClass().lowercase( pTableFormat->GetName() ));
147 0 : if ( sNm == pItem->m_Item )
148 : {
149 : SwTable* pTmpTable;
150 : SwTableBox* pFBox;
151 0 : if( 0 != ( pTmpTable = SwTable::FindTable( pTableFormat ) ) &&
152 0 : 0 != ( pFBox = pTmpTable->GetTabSortBoxes()[0] ) &&
153 0 : pFBox->GetSttNd() &&
154 0 : &pTableFormat->GetDoc()->GetNodes() == &pFBox->GetSttNd()->GetNodes() )
155 : {
156 : // a table in the normal NodesArr
157 : pItem->pTableNd = const_cast<SwTableNode*>(
158 0 : pFBox->GetSttNd()->FindTableNode());
159 0 : return false;
160 : }
161 : // If the name is already correct, but not the rest then we don't have them.
162 : // The names are always unique.
163 : }
164 0 : return true;
165 : }
166 :
167 : }
168 :
169 :
170 : namespace sw
171 : {
172 :
173 2958 : DocumentLinksAdministrationManager::DocumentLinksAdministrationManager( SwDoc& i_rSwdoc ) : mbVisibleLinks(true),
174 : mbLinksUpdated( false ), //#i38810#
175 2958 : mpLinkMgr( new sfx2::LinkManager( 0 ) ),
176 5916 : m_rDoc( i_rSwdoc )
177 : {
178 2958 : }
179 :
180 19 : bool DocumentLinksAdministrationManager::IsVisibleLinks() const
181 : {
182 19 : return mbVisibleLinks;
183 : }
184 :
185 2 : void DocumentLinksAdministrationManager::SetVisibleLinks(bool bFlag)
186 : {
187 2 : mbVisibleLinks = bFlag;
188 2 : }
189 :
190 40555 : sfx2::LinkManager& DocumentLinksAdministrationManager::GetLinkManager()
191 : {
192 40555 : return *mpLinkMgr;
193 : }
194 :
195 0 : const sfx2::LinkManager& DocumentLinksAdministrationManager::GetLinkManager() const
196 : {
197 0 : return *mpLinkMgr;
198 : }
199 :
200 : // #i42634# Moved common code of SwReader::Read() and SwDocShell::UpdateLinks()
201 : // to new SwDoc::UpdateLinks():
202 2398 : void DocumentLinksAdministrationManager::UpdateLinks( bool bUI )
203 : {
204 : SfxObjectCreateMode eMode;
205 2398 : sal_uInt16 nLinkMode = m_rDoc.GetDocumentSettingManager().getLinkUpdateMode( true );
206 2398 : if ( m_rDoc.GetDocShell()) {
207 2398 : sal_uInt16 nUpdateDocMode = m_rDoc.GetDocShell()->GetUpdateDocMode();
208 4796 : if( (nLinkMode != NEVER || document::UpdateDocMode::FULL_UPDATE == nUpdateDocMode) &&
209 2412 : !GetLinkManager().GetLinks().empty() &&
210 : SfxObjectCreateMode::INTERNAL !=
211 28 : ( eMode = m_rDoc.GetDocShell()->GetCreateMode()) &&
212 14 : SfxObjectCreateMode::ORGANIZER != eMode &&
213 2412 : SfxObjectCreateMode::PREVIEW != eMode &&
214 14 : !m_rDoc.GetDocShell()->IsPreview() )
215 : {
216 14 : bool bAskUpdate = nLinkMode == MANUAL;
217 14 : bool bUpdate = true;
218 14 : switch(nUpdateDocMode)
219 : {
220 14 : case document::UpdateDocMode::NO_UPDATE: bUpdate = false;break;
221 0 : case document::UpdateDocMode::QUIET_UPDATE:bAskUpdate = false; break;
222 0 : case document::UpdateDocMode::FULL_UPDATE: bAskUpdate = true; break;
223 : }
224 14 : if( bUpdate && (bUI || !bAskUpdate) )
225 : {
226 0 : SfxMedium* pMedium = m_rDoc.GetDocShell()->GetMedium();
227 0 : SfxFrame* pFrm = pMedium ? pMedium->GetLoadTargetFrame() : 0;
228 0 : vcl::Window* pDlgParent = pFrm ? &pFrm->GetWindow() : 0;
229 :
230 0 : GetLinkManager().UpdateAllLinks( bAskUpdate, true, false, pDlgParent );
231 : }
232 : }
233 : }
234 2398 : }
235 :
236 0 : bool DocumentLinksAdministrationManager::GetData( const OUString& rItem, const OUString& rMimeType,
237 : uno::Any & rValue ) const
238 : {
239 : // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
240 0 : bool bCaseSensitive = true;
241 : while( true )
242 : {
243 0 : ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
244 0 : if(pBkmk)
245 0 : return SwServerObject(*pBkmk).GetData(rValue, rMimeType);
246 :
247 : // Do we already have the Item?
248 0 : OUString sItem( bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem));
249 0 : _FindItem aPara( sItem );
250 0 : for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
251 : {
252 0 : if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
253 0 : break;
254 : }
255 0 : if( aPara.pSectNd )
256 : {
257 : // found, so get the data
258 0 : return SwServerObject( *aPara.pSectNd ).GetData( rValue, rMimeType );
259 : }
260 0 : if( !bCaseSensitive )
261 0 : break;
262 0 : bCaseSensitive = false;
263 0 : }
264 :
265 0 : _FindItem aPara( GetAppCharClass().lowercase( rItem ));
266 0 : for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
267 : {
268 0 : if (!(lcl_FindTable(pFormat, &aPara)))
269 0 : break;
270 : }
271 0 : if( aPara.pTableNd )
272 : {
273 0 : return SwServerObject( *aPara.pTableNd ).GetData( rValue, rMimeType );
274 : }
275 :
276 0 : return false;
277 : }
278 :
279 0 : bool DocumentLinksAdministrationManager::SetData( const OUString& rItem, const OUString& ,
280 : const uno::Any & )
281 : {
282 : // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
283 0 : bool bCaseSensitive = true;
284 : while( true )
285 : {
286 0 : ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
287 0 : if(pBkmk)
288 : {
289 0 : return false;
290 : }
291 :
292 : // Do we already have the Item?
293 0 : OUString sItem( bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem));
294 0 : _FindItem aPara( sItem );
295 0 : for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
296 : {
297 0 : if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
298 0 : break;
299 : }
300 0 : if( aPara.pSectNd )
301 : {
302 : // found, so get the data
303 0 : return false;
304 : }
305 0 : if( !bCaseSensitive )
306 0 : break;
307 0 : bCaseSensitive = false;
308 0 : }
309 :
310 0 : OUString sItem(GetAppCharClass().lowercase(rItem));
311 0 : _FindItem aPara( sItem );
312 0 : for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
313 : {
314 0 : if (!(lcl_FindTable(pFormat, &aPara)))
315 0 : break;
316 : }
317 :
318 0 : return false;
319 : }
320 :
321 1 : ::sfx2::SvLinkSource* DocumentLinksAdministrationManager::CreateLinkSource(const OUString& rItem)
322 : {
323 1 : SwServerObject* pObj = NULL;
324 :
325 : // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
326 1 : bool bCaseSensitive = true;
327 : while( true )
328 : {
329 : // bookmarks
330 1 : ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), rItem, bCaseSensitive);
331 2 : if(pBkmk && pBkmk->IsExpanded()
332 2 : && (0 == (pObj = pBkmk->GetRefObject())))
333 : {
334 : // mark found, but no link yet -> create hotlink
335 1 : pObj = new SwServerObject(*pBkmk);
336 1 : pBkmk->SetRefObject(pObj);
337 1 : GetLinkManager().InsertServer(pObj);
338 : }
339 1 : if(pObj)
340 2 : return pObj;
341 :
342 0 : _FindItem aPara(bCaseSensitive ? rItem : GetAppCharClass().lowercase(rItem));
343 : // sections
344 0 : for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
345 : {
346 0 : if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
347 0 : break;
348 : }
349 :
350 0 : if(aPara.pSectNd
351 0 : && (0 == (pObj = aPara.pSectNd->GetSection().GetObject())))
352 : {
353 : // section found, but no link yet -> create hotlink
354 0 : pObj = new SwServerObject( *aPara.pSectNd );
355 0 : aPara.pSectNd->GetSection().SetRefObject( pObj );
356 0 : GetLinkManager().InsertServer(pObj);
357 : }
358 0 : if(pObj)
359 0 : return pObj;
360 0 : if( !bCaseSensitive )
361 0 : break;
362 0 : bCaseSensitive = false;
363 0 : }
364 :
365 0 : _FindItem aPara( GetAppCharClass().lowercase(rItem) );
366 : // tables
367 0 : for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
368 : {
369 0 : if (!(lcl_FindTable(pFormat, &aPara)))
370 0 : break;
371 : }
372 0 : if(aPara.pTableNd
373 0 : && (0 == (pObj = aPara.pTableNd->GetTable().GetObject())))
374 : {
375 : // table found, but no link yet -> create hotlink
376 0 : pObj = new SwServerObject(*aPara.pTableNd);
377 0 : aPara.pTableNd->GetTable().SetRefObject(pObj);
378 0 : GetLinkManager().InsertServer(pObj);
379 : }
380 0 : return pObj;
381 : }
382 :
383 : /// embedded all local links (Areas/Graphics)
384 47 : bool DocumentLinksAdministrationManager::EmbedAllLinks()
385 : {
386 47 : bool bRet = false;
387 47 : sfx2::LinkManager& rLnkMgr = GetLinkManager();
388 47 : const ::sfx2::SvBaseLinks& rLinks = rLnkMgr.GetLinks();
389 47 : if( !rLinks.empty() )
390 : {
391 0 : ::sw::UndoGuard const undoGuard(m_rDoc.GetIDocumentUndoRedo());
392 :
393 0 : ::sfx2::SvBaseLink* pLnk = 0;
394 0 : while( 0 != (pLnk = lcl_FindNextRemovableLink( rLinks ) ) )
395 : {
396 0 : ::sfx2::SvBaseLinkRef xLink = pLnk;
397 : // Tell the link that it's being destroyed!
398 0 : xLink->Closed();
399 :
400 : // if one forgot to remove itself
401 0 : if( xLink.Is() )
402 0 : rLnkMgr.Remove( xLink );
403 :
404 0 : bRet = true;
405 0 : }
406 :
407 0 : m_rDoc.GetIDocumentUndoRedo().DelAllUndoObj();
408 0 : m_rDoc.getIDocumentState().SetModified();
409 : }
410 47 : return bRet;
411 : }
412 :
413 121 : void DocumentLinksAdministrationManager::SetLinksUpdated(const bool bNewLinksUpdated)
414 : {
415 121 : mbLinksUpdated = bNewLinksUpdated;
416 121 : }
417 :
418 859 : bool DocumentLinksAdministrationManager::LinksUpdated() const
419 : {
420 859 : return mbLinksUpdated;
421 : }
422 :
423 8847 : DocumentLinksAdministrationManager::~DocumentLinksAdministrationManager()
424 : {
425 2949 : DELETEZ( mpLinkMgr );
426 5898 : }
427 :
428 0 : bool DocumentLinksAdministrationManager::SelectServerObj( const OUString& rStr, SwPaM*& rpPam, SwNodeRange*& rpRange ) const
429 : {
430 : // Do we actually have the Item?
431 0 : rpPam = 0;
432 0 : rpRange = 0;
433 :
434 : OUString sItem( INetURLObject::decode( rStr,
435 : INetURLObject::DECODE_WITH_CHARSET,
436 0 : RTL_TEXTENCODING_UTF8 ));
437 :
438 0 : sal_Int32 nPos = sItem.indexOf( cMarkSeparator );
439 :
440 0 : const CharClass& rCC = GetAppCharClass();
441 :
442 : // Extension for sections: not only link bookmarks/sections
443 : // but also frames (text!), tables, outlines:
444 0 : if( -1 != nPos )
445 : {
446 0 : bool bContinue = false;
447 0 : OUString sName( sItem.copy( 0, nPos ) );
448 0 : OUString sCmp( sItem.copy( nPos + 1 ));
449 0 : sItem = rCC.lowercase( sItem );
450 :
451 0 : _FindItem aPara( sName );
452 :
453 0 : if( sCmp == "table" )
454 : {
455 0 : sName = rCC.lowercase( sName );
456 0 : for( const SwFrameFormat* pFormat : *m_rDoc.GetTableFrameFormats() )
457 : {
458 0 : if (!(lcl_FindTable(pFormat, &aPara)))
459 0 : break;
460 : }
461 0 : if( aPara.pTableNd )
462 : {
463 : rpRange = new SwNodeRange( *aPara.pTableNd, 0,
464 0 : *aPara.pTableNd->EndOfSectionNode(), 1 );
465 0 : return true;
466 : }
467 : }
468 0 : else if( sCmp == "frame" )
469 : {
470 : SwNodeIndex* pIdx;
471 : SwNode* pNd;
472 0 : const SwFlyFrameFormat* pFlyFormat = m_rDoc.FindFlyByName( sName );
473 0 : if( pFlyFormat &&
474 0 : 0 != ( pIdx = const_cast<SwNodeIndex*>(pFlyFormat->GetContent().GetContentIdx()) ) &&
475 0 : !( pNd = &pIdx->GetNode())->IsNoTextNode() )
476 : {
477 0 : rpRange = new SwNodeRange( *pNd, 1, *pNd->EndOfSectionNode() );
478 0 : return true;
479 : }
480 : }
481 0 : else if( sCmp == "region" )
482 : {
483 0 : sItem = sName; // Is being dealt with further down!
484 0 : bContinue = true;
485 : }
486 0 : else if( sCmp == "outline" )
487 : {
488 0 : SwPosition aPos( SwNodeIndex( (SwNodes&)m_rDoc.GetNodes() ));
489 0 : if( m_rDoc.GotoOutline( aPos, sName ))
490 : {
491 0 : SwNode* pNd = &aPos.nNode.GetNode();
492 0 : const int nLvl = pNd->GetTextNode()->GetAttrOutlineLevel()-1;
493 :
494 0 : const SwOutlineNodes& rOutlNds = m_rDoc.GetNodes().GetOutLineNds();
495 : sal_uInt16 nTmpPos;
496 0 : (void)rOutlNds.Seek_Entry( pNd, &nTmpPos );
497 0 : rpRange = new SwNodeRange( aPos.nNode, 0, aPos.nNode );
498 :
499 : // look for the section's end, now
500 0 : for( ++nTmpPos;
501 0 : nTmpPos < rOutlNds.size() &&
502 0 : nLvl < rOutlNds[ nTmpPos ]->GetTextNode()->
503 0 : GetAttrOutlineLevel()-1;
504 : ++nTmpPos )
505 : ; // there is no block
506 :
507 0 : if( nTmpPos < rOutlNds.size() )
508 0 : rpRange->aEnd = *rOutlNds[ nTmpPos ];
509 : else
510 0 : rpRange->aEnd = m_rDoc.GetNodes().GetEndOfContent();
511 0 : return true;
512 0 : }
513 : }
514 :
515 0 : if( !bContinue )
516 0 : return false;
517 : }
518 :
519 : // search for bookmarks and sections case sensitive at first. If nothing is found then try again case insensitive
520 0 : bool bCaseSensitive = true;
521 : while( true )
522 : {
523 0 : ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*m_rDoc.getIDocumentMarkAccess(), sItem, bCaseSensitive);
524 0 : if(pBkmk)
525 : {
526 0 : if(pBkmk->IsExpanded())
527 : rpPam = new SwPaM(
528 0 : pBkmk->GetMarkPos(),
529 0 : pBkmk->GetOtherMarkPos());
530 0 : return static_cast<bool>(rpPam);
531 : }
532 :
533 0 : _FindItem aPara( bCaseSensitive ? sItem : rCC.lowercase( sItem ) );
534 :
535 0 : if( !m_rDoc.GetSections().empty() )
536 : {
537 0 : for( const SwSectionFormat* pFormat : m_rDoc.GetSections() )
538 : {
539 0 : if (!(lcl_FindSection(pFormat, &aPara, bCaseSensitive)))
540 0 : break;
541 : }
542 0 : if( aPara.pSectNd )
543 : {
544 : rpRange = new SwNodeRange( *aPara.pSectNd, 1,
545 0 : *aPara.pSectNd->EndOfSectionNode() );
546 0 : return true;
547 :
548 : }
549 : }
550 0 : if( !bCaseSensitive )
551 0 : break;
552 0 : bCaseSensitive = false;
553 0 : }
554 0 : return false;
555 : }
556 :
557 :
558 :
559 177 : }
560 :
561 :
562 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|