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 <vcl/svapp.hxx>
21 
22 #include <osl/diagnose.h>
23 #include <sfx2/lnkbase.hxx>
24 #include <editeng/boxitem.hxx>
25 #include <sfx2/linkmgr.hxx>
26 #include <sfx2/event.hxx>
27 #include <sot/exchange.hxx>
28 #include <fmtfsize.hxx>
29 #include <fmtanchr.hxx>
30 #include <frmatr.hxx>
31 #include <frmfmt.hxx>
32 #include <doc.hxx>
33 #include <IDocumentLayoutAccess.hxx>
34 #include <IDocumentLinksAdministration.hxx>
35 #include <pam.hxx>
36 #include <swtable.hxx>
37 #include <swevent.hxx>
38 #include <swbaslnk.hxx>
39 #include <swserv.hxx>
40 #include <viewsh.hxx>
41 #include <ndgrf.hxx>
42 #include <htmltbl.hxx>
43 #include <dialoghelp.hxx>
44 #include <memory>
45 
46 using namespace com::sun::star;
47 
48 static bool SetGrfFlySize( const Size& rGrfSz, SwGrfNode* pGrfNd, const Size &rOrigGrfSize );
49 
50 
DataChanged(const OUString & rMimeType,const uno::Any & rValue)51 ::sfx2::SvBaseLink::UpdateResult SwBaseLink::DataChanged(
52     const OUString& rMimeType, const uno::Any & rValue )
53 {
54     if( !m_pContentNode )
55     {
56         OSL_ENSURE(false, "DataChanged without ContentNode" );
57         return ERROR_GENERAL;
58     }
59 
60     SwDoc& rDoc = m_pContentNode->GetDoc();
61     if( rDoc.IsInDtor() || ChkNoDataFlag() )
62     {
63         return SUCCESS;
64     }
65 
66     SotClipboardFormatId nFormat = SotExchange::GetFormatIdFromMimeType( rMimeType );
67 
68     if( m_pContentNode->IsNoTextNode() &&
69         nFormat == sfx2::LinkManager::RegisterStatusInfoId() )
70     {
71         // Only a status change - serve Events?
72         OUString sState;
73 
74         if( rValue.hasValue() && ( rValue >>= sState ))
75         {
76             SvMacroItemId nEvent = SvMacroItemId::NONE;
77             switch( sState.toInt32() )
78             {
79             case sfx2::LinkManager::STATE_LOAD_OK:      nEvent = SvMacroItemId::OnImageLoadDone;  break;
80             case sfx2::LinkManager::STATE_LOAD_ERROR:   nEvent = SvMacroItemId::OnImageLoadError; break;
81             case sfx2::LinkManager::STATE_LOAD_ABORT:   nEvent = SvMacroItemId::OnImageLoadCancel; break;
82             }
83 
84             SwFrameFormat* pFormat;
85             if( nEvent != SvMacroItemId::NONE && nullptr != ( pFormat = m_pContentNode->GetFlyFormat() ))
86             {
87                 SwCallMouseEvent aCallEvent;
88                 aCallEvent.Set( EVENT_OBJECT_IMAGE, pFormat );
89                 rDoc.CallEvent( nEvent, aCallEvent );
90             }
91         }
92         return SUCCESS; // That's it!
93     }
94 
95     bool bUpdate = false;
96     bool bFrameInPaint = false;
97     Size aGrfSz, aOldSz;
98 
99     SwGrfNode* pSwGrfNode = nullptr;
100 
101     if (m_pContentNode->IsGrfNode())
102     {
103         pSwGrfNode = m_pContentNode->GetGrfNode();
104         assert(pSwGrfNode && "Error, pSwGrfNode expected when node answers IsGrfNode() with true (!)");
105         aOldSz = pSwGrfNode->GetTwipSize();
106         const GraphicObject& rGrfObj = pSwGrfNode->GetGrfObj();
107 
108         bFrameInPaint = pSwGrfNode->IsFrameInPaint();
109 
110         Graphic aGrf;
111 
112         // tdf#124698 if any auth dialog is needed, find what the parent window should be
113         weld::Window* pDlgParent = GetFrameWeld(&rDoc);
114 
115         if (rDoc.getIDocumentLinksAdministration().GetLinkManager().GetGraphicFromAny(rMimeType, rValue, aGrf, pDlgParent) &&
116             ( GraphicType::Default != aGrf.GetType() ||
117               GraphicType::Default != rGrfObj.GetType() ) )
118         {
119             aGrfSz = ::GetGraphicSizeTwip( aGrf, nullptr );
120 
121             pSwGrfNode->SetGraphic(aGrf);
122             bUpdate = true;
123 
124             // Always use the correct graphic size
125             if( aGrfSz.Height() && aGrfSz.Width() &&
126                 aOldSz.Height() && aOldSz.Width() &&
127                 aGrfSz != aOldSz )
128             {
129                 pSwGrfNode->SetTwipSize(aGrfSz);
130                 aOldSz = aGrfSz;
131             }
132         }
133     }
134     else if( m_pContentNode->IsOLENode() )
135         bUpdate = true;
136 
137     if ( !bUpdate || bFrameInPaint )
138         return SUCCESS;
139 
140     if(pSwGrfNode && !SetGrfFlySize(aGrfSz, pSwGrfNode, aOldSz))
141         pSwGrfNode->TriggerGraphicArrived();
142 
143     return SUCCESS;
144 }
145 
SetGrfFlySize(const Size & rGrfSz,SwGrfNode * pGrfNd,const Size & rOrigGrfSize)146 static bool SetGrfFlySize( const Size& rGrfSz, SwGrfNode* pGrfNd, const Size& rOrigGrfSize )
147 {
148     bool bRet = false;
149     SwViewShell *pSh = pGrfNd->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
150     std::unique_ptr<CurrShell> pCurr;
151     if ( pGrfNd->GetDoc().GetEditShell() )
152         pCurr.reset(new CurrShell( pSh ));
153 
154     Size aSz = rOrigGrfSize;
155     if ( !(aSz.Width() && aSz.Height()) &&
156             rGrfSz.Width() && rGrfSz.Height() )
157     {
158         SwFrameFormat* pFormat = nullptr;
159         if (pGrfNd->IsChgTwipSize())
160             pFormat = pGrfNd->GetFlyFormat();
161         if (nullptr != pFormat)
162         {
163             Size aCalcSz( aSz );
164             if ( !aSz.Height() && aSz.Width() )
165                 // Calculate the right height
166                 aCalcSz.setHeight( rGrfSz.Height() *
167                         aSz.Width() / rGrfSz.Width() );
168             else if ( !aSz.Width() && aSz.Height() )
169                 // Calculate the right width
170                 aCalcSz.setWidth( rGrfSz.Width() *
171                         aSz.Height() / rGrfSz.Height() );
172             else
173                 // Take over height and width
174                 aCalcSz = rGrfSz;
175 
176             const SvxBoxItem     &rBox = pFormat->GetBox();
177             aCalcSz.AdjustWidth(rBox.CalcLineSpace(SvxBoxItemLine::LEFT) +
178                                rBox.CalcLineSpace(SvxBoxItemLine::RIGHT) );
179             aCalcSz.AdjustHeight(rBox.CalcLineSpace(SvxBoxItemLine::TOP) +
180                                rBox.CalcLineSpace(SvxBoxItemLine::BOTTOM) );
181             const SwFormatFrameSize& rOldAttr = pFormat->GetFrameSize();
182             if( rOldAttr.GetSize() != aCalcSz )
183             {
184                 SwFormatFrameSize aAttr( rOldAttr  );
185                 aAttr.SetSize( aCalcSz );
186                 pFormat->SetFormatAttr( aAttr );
187                 bRet = true;
188             }
189 
190             if( !aSz.Width() )
191             {
192                 // If the graphic is anchored in a table, we need to recalculate
193                 // the table rows
194                 const SwDoc& rDoc = pGrfNd->GetDoc();
195                 const SwPosition* pAPos = pFormat->GetAnchor().GetContentAnchor();
196                 SwTableNode *pTableNd;
197                 if (pAPos && nullptr != (pTableNd = pAPos->nNode.GetNode().FindTableNode()))
198                 {
199                     const bool bLastGrf = !pTableNd->GetTable().DecGrfsThatResize();
200                     SwHTMLTableLayout *pLayout =
201                         pTableNd->GetTable().GetHTMLTableLayout();
202                     if( pLayout )
203                     {
204                         const sal_uInt16 nBrowseWidth =
205                                     pLayout->GetBrowseWidthByTable( rDoc );
206                         if ( nBrowseWidth )
207                         {
208                             pLayout->Resize( nBrowseWidth, true, true,
209                                              bLastGrf ? HTMLTABLE_RESIZE_NOW
210                                                       : 500 );
211                         }
212                     }
213                 }
214             }
215         }
216 
217         // SetTwipSize rescales an ImageMap if needed for which
218         // it requires the Frame Format
219         pGrfNd->SetTwipSize( rGrfSz );
220     }
221 
222     return bRet;
223 }
224 
SwapIn(bool bWaitForData,bool bNativFormat)225 bool SwBaseLink::SwapIn( bool bWaitForData, bool bNativFormat )
226 {
227     if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) ))
228     {
229         AddNextRef();
230         GetRealObject_();
231         ReleaseRef();
232     }
233 
234     bool bRes = false;
235 
236     if( GetObj() )
237     {
238         OUString aMimeType( SotExchange::GetFormatMimeType( GetContentType() ));
239         uno::Any aValue;
240         (void)GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData );
241 
242         if( bWaitForData && !GetObj() )
243         {
244             OSL_ENSURE( false, "The SvxFileObject was deleted in a GetData!" );
245         }
246         else
247         {
248             bRes = aValue.hasValue();
249             if ( bRes )
250             {
251                 DataChanged( aMimeType, aValue );
252             }
253         }
254     }
255     else if( !IsSynchron() && bWaitForData )
256     {
257         SetSynchron( true );
258         bRes = Update();
259         SetSynchron( false );
260     }
261     else
262         bRes = Update();
263 
264     return bRes;
265 }
266 
Closed()267 void SwBaseLink::Closed()
268 {
269     if( m_pContentNode && !m_pContentNode->GetDoc().IsInDtor() )
270     {
271         // Delete the connection
272         if( m_pContentNode->IsGrfNode() )
273             static_cast<SwGrfNode*>(m_pContentNode)->ReleaseLink();
274     }
275     SvBaseLink::Closed();
276 }
277 
GetAnchor() const278 const SwNode* SwBaseLink::GetAnchor() const
279 {
280     if (m_pContentNode)
281     {
282         SwFrameFormat *const pFormat = m_pContentNode->GetFlyFormat();
283         if (pFormat)
284         {
285             const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
286             SwPosition const*const pAPos = rAnchor.GetContentAnchor();
287             if (pAPos &&
288                 ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
289                  (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
290                  (RndStdIds::FLY_AT_FLY  == rAnchor.GetAnchorId()) ||
291                  (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId())))
292             {
293                     return &pAPos->nNode.GetNode();
294             }
295             return nullptr;
296         }
297     }
298 
299     OSL_ENSURE( false, "GetAnchor is not shadowed" );
300     return nullptr;
301 }
302 
IsRecursion(const SwBaseLink * pChkLnk) const303 bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const
304 {
305     tools::SvRef<SwServerObject> aRef( static_cast<SwServerObject*>(GetObj()) );
306     if( aRef.is() )
307     {
308         // As it's a ServerObject, we query all contained Links
309         // if we are contained in them. Else we have a recursion.
310         return aRef->IsLinkInServer( pChkLnk );
311     }
312     return false;
313 }
314 
IsInRange(sal_uLong,sal_uLong) const315 bool SwBaseLink::IsInRange( sal_uLong, sal_uLong ) const
316 {
317     // Not Graphic or OLE Links
318     // Fields or Sections have their own derivation!
319     return false;
320 }
321 
~SwBaseLink()322 SwBaseLink::~SwBaseLink()
323 {
324 }
325 
326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
327