1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <config_features.h>
22 #include <officecfg/Office/Common.hxx>
23 #include <editeng/sizeitem.hxx>
24 #include <sal/log.hxx>
25 #include <sfx2/lokhelper.hxx>
26 #include <sfx2/opengrf.hxx>
27 #include <sfx2/viewfrm.hxx>
28 #include <svx/svdograf.hxx>
29 #include <svx/svdomedia.hxx>
30 #include <svx/svdpage.hxx>
31 #include <svx/svdpagv.hxx>
32 #include <svx/svdview.hxx>
33 #include <svx/linkwarn.hxx>
34 #include <svx/svxids.hrc>
35 #include <vcl/graphicfilter.hxx>
36 #include <svl/stritem.hxx>
37 #include <avmedia/mediawindow.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/weld.hxx>
40 #include <vcl/GraphicNativeTransform.hxx>
41 #include <vcl/GraphicNativeMetadata.hxx>
42 #include <fuinsert.hxx>
43 #include <tabvwsh.hxx>
44 #include <drwlayer.hxx>
45 #include <drawview.hxx>
46 #include <document.hxx>
47 #include <scresid.hxx>
48 #include <strings.hrc>
49 #include <globstr.hrc>
50 #include <comphelper/lok.hxx>
52 #include <tools/hostfilter.hxx>
53 #include <tools/urlobj.hxx>
55 #include <com/sun/star/frame/XDispatchProvider.hpp>
56 #include <com/sun/star/media/XPlayer.hpp>
57 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
58 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
59 #include <com/sun/star/ui/dialogs/ListboxControlActions.hpp>
60 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
61 #include <com/sun/star/uno/Sequence.hxx>
64 using namespace css::uno
;
66 void ScLimitSizeOnDrawPage( Size
& rSize
, Point
& rPos
, const Size
& rPage
)
68 if ( !rPage
.Width() || !rPage
.Height() )
71 Size aPageSize
= rPage
;
72 bool bNegative
= aPageSize
.Width() < 0;
75 // make everything positive temporarily
76 aPageSize
.setWidth( -aPageSize
.Width() );
77 rPos
.setX( -rPos
.X() - rSize
.Width() );
80 if ( rSize
.Width() > aPageSize
.Width() || rSize
.Height() > aPageSize
.Height() )
82 double fX
= aPageSize
.Width() / static_cast<double>(rSize
.Width());
83 double fY
= aPageSize
.Height() / static_cast<double>(rSize
.Height());
87 rSize
.setWidth( aPageSize
.Width() );
88 rSize
.setHeight( static_cast<tools::Long
>( rSize
.Height() * fX
) );
92 rSize
.setHeight( aPageSize
.Height() );
93 rSize
.setWidth( static_cast<tools::Long
>( rSize
.Width() * fY
) );
102 if ( rPos
.X() + rSize
.Width() > aPageSize
.Width() )
103 rPos
.setX( aPageSize
.Width() - rSize
.Width() );
104 if ( rPos
.Y() + rSize
.Height() > aPageSize
.Height() )
105 rPos
.setY( aPageSize
.Height() - rSize
.Height() );
108 rPos
.setX( -rPos
.X() - rSize
.Width() ); // back to real position
111 static void lcl_InsertGraphic( const Graphic
& rGraphic
,
112 const OUString
& rFileName
, bool bAsLink
, bool bApi
,
113 ScTabViewShell
& rViewSh
, const vcl::Window
* pWindow
, SdrView
* pView
,
114 ScAnchorType aAnchorType
= SCA_CELL
)
116 Graphic
& rGraphic1
= const_cast<Graphic
&>(rGraphic
);
117 GraphicNativeMetadata aMetadata
;
118 if ( aMetadata
.read(rGraphic1
) )
120 const Degree10 aRotation
= aMetadata
.getRotation();
123 GraphicNativeTransform
aTransform( rGraphic1
);
124 aTransform
.rotate( aRotation
);
127 ScDrawView
* pDrawView
= rViewSh
.GetScDrawView();
129 // #i123922# check if an existing object is selected; if yes, evtl. replace
130 // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
131 // style for other objects
134 const SdrMarkList
& rMarkList
= pDrawView
->GetMarkedObjectList();
135 if (1 == rMarkList
.GetMarkCount())
137 SdrObject
* pPickObj
= rMarkList
.GetMark(0)->GetMarkedSdrObj();
141 //sal_Int8 nAction(DND_ACTION_MOVE);
143 const OUString
aBeginUndo(ScResId(STR_UNDO_DRAGDROP
));
145 SdrObject
* pResult
= pDrawView
->ApplyGraphicToObject(
149 bAsLink
? rFileName
: OUString());
153 // we are done; mark the modified/new object
154 pDrawView
->MarkObj(pResult
, pDrawView
->GetSdrPageView());
161 // set the size so the graphic has its original pixel size
162 // at 100% view scale (as in SetMarkedOriginalSize),
163 // instead of respecting the current view scale
164 MapMode aSourceMap
= rGraphic
.GetPrefMapMode();
165 MapMode
aDestMap( MapUnit::Map100thMM
);
166 if ( aSourceMap
.GetMapUnit() == MapUnit::MapPixel
&& pDrawView
)
168 Fraction aScaleX
, aScaleY
;
169 pDrawView
->CalcNormScale( aScaleX
, aScaleY
);
170 aDestMap
.SetScaleX(aScaleX
);
171 aDestMap
.SetScaleY(aScaleY
);
173 Size aLogicSize
= pWindow
->LogicToLogic(
174 rGraphic
.GetPrefSize(), &aSourceMap
, &aDestMap
);
178 SdrPageView
* pPV
= pView
->GetSdrPageView();
179 SdrPage
* pPage
= pPV
->GetPage();
180 Point aInsertPos
= rViewSh
.GetInsertPos();
182 ScViewData
& rData
= rViewSh
.GetViewData();
183 if ( rData
.GetDocument().IsNegativePage( rData
.GetTabNo() ) )
184 aInsertPos
.AdjustX( -(aLogicSize
.Width()) ); // move position to left edge
186 ScLimitSizeOnDrawPage( aLogicSize
, aInsertPos
, pPage
->GetSize() );
188 tools::Rectangle
aRect ( aInsertPos
, aLogicSize
);
190 rtl::Reference
<SdrGrafObj
> pObj
= new SdrGrafObj(
191 pView
->getSdrModelFromSdrView(), // TTTT pView should be reference
195 // calling SetGraphicLink here doesn't work
196 // Yes, due to the SdrObject had no SdrModel
197 // Path is no longer used as name for the graphics object
199 ScDrawLayer
* pLayer
= static_cast<ScDrawLayer
*>(&pView
->GetModel());
200 OUString aName
= pLayer
->GetNewGraphicName(); // "Graphics"
201 pObj
->SetName(aName
);
203 if (aAnchorType
== SCA_CELL
|| aAnchorType
== SCA_CELL_RESIZE
)
204 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, rData
.GetDocument(), rData
.GetTabNo(),
205 aAnchorType
== SCA_CELL_RESIZE
);
207 // don't select if from (dispatch) API, to allow subsequent cell operations
208 SdrInsertFlags nInsOptions
= (bApi
&& !comphelper::LibreOfficeKit::isActive()) ? SdrInsertFlags::DONTMARK
: SdrInsertFlags::NONE
;
209 bool bSuccess
= pView
->InsertObjectAtView( pObj
.get(), *pPV
, nInsOptions
);
211 // SetGraphicLink has to be used after inserting the object,
212 // otherwise an empty graphic is swapped in and the contact stuff crashes.
214 if (bSuccess
&& bAsLink
)
215 pObj
->SetGraphicLink( rFileName
);
218 #if HAVE_FEATURE_AVMEDIA
220 static void lcl_InsertMedia( const OUString
& rMediaURL
, bool bApi
,
221 ScTabViewShell
* pViewSh
, const vcl::Window
* pWindow
, SdrView
* pView
,
222 const Size
& rPrefSize
, bool const bLink
)
224 SdrPageView
* pPV
= pView
->GetSdrPageView();
225 SdrPage
* pPage
= pPV
->GetPage();
226 ScViewData
& rData
= pViewSh
->GetViewData();
227 Point
aInsertPos( pViewSh
->GetInsertPos() );
230 if( rPrefSize
.Width() && rPrefSize
.Height() )
233 aSize
= pWindow
->PixelToLogic(rPrefSize
, MapMode(MapUnit::Map100thMM
));
235 aSize
= Application::GetDefaultDevice()->PixelToLogic(rPrefSize
, MapMode(MapUnit::Map100thMM
));
238 aSize
= Size( 5000, 5000 );
240 ScLimitSizeOnDrawPage( aSize
, aInsertPos
, pPage
->GetSize() );
242 if( rData
.GetDocument().IsNegativePage( rData
.GetTabNo() ) )
243 aInsertPos
.AdjustX( -(aSize
.Width()) );
252 uno::Reference
<frame::XModel
> const xModel(
253 rData
.GetDocument().GetDocumentShell()->GetModel());
254 bool const bRet
= ::avmedia::EmbedMedia(xModel
, rMediaURL
, realURL
);
255 if (!bRet
) { return; }
258 rtl::Reference
<SdrMediaObj
> pObj
= new SdrMediaObj(
259 *rData
.GetDocument().GetDrawLayer(),
260 tools::Rectangle(aInsertPos
, aSize
));
262 pObj
->setURL( realURL
, u
""_ustr
/*TODO?*/ );
263 pView
->InsertObjectAtView( pObj
.get(), *pPV
, bApi
? SdrInsertFlags::DONTMARK
: SdrInsertFlags::NONE
);
267 FuInsertGraphic::FuInsertGraphic( ScTabViewShell
& rViewSh
,
272 : FuPoor(rViewSh
, pWin
, pViewP
, pDoc
, rReq
)
274 const SfxItemSet
* pReqArgs
= rReq
.GetArgs();
275 const SfxStringItem
* pGraphicItem
;
277 (pGraphicItem
= pReqArgs
->GetItemIfSet( SID_INSERT_GRAPHIC
, true )) )
279 const OUString
& aFileName
= pGraphicItem
->GetValue();
281 OUString aFilterName
;
282 if ( const SfxStringItem
* pFilterItem
= pReqArgs
->GetItemIfSet( FN_PARAM_FILTER
) )
283 aFilterName
= pFilterItem
->GetValue();
285 bool bAsLink
= false;
286 const SfxPoolItem
* pItem
;
287 if ( pReqArgs
->GetItemState( FN_PARAM_1
, true, &pItem
) == SfxItemState::SET
)
288 bAsLink
= static_cast<const SfxBoolItem
*>(pItem
)->GetValue();
290 if (comphelper::LibreOfficeKit::isActive())
292 INetURLObject
aURL(aFileName
);
293 if (INetProtocol::File
!= aURL
.GetProtocol() && HostFilter::isForbidden(aURL
.GetHost()))
294 SfxLokHelper::sendNetworkAccessError("insert");
298 ErrCode nError
= GraphicFilter::LoadGraphic( aFileName
, aFilterName
, aGraphic
, &GraphicFilter::GetGraphicFilter() );
299 if ( nError
== ERRCODE_NONE
)
301 lcl_InsertGraphic( aGraphic
, aFileName
, bAsLink
, true, rViewSh
, pWindow
, pView
);
306 SvxOpenGraphicDialog
aDlg(ScResId(STR_INSERTGRAPHIC
), pWin
? pWin
->GetFrameWeld() : nullptr,
307 ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
);
309 Reference
<ui::dialogs::XFilePickerControlAccess
> xCtrlAcc
= aDlg
.GetFilePickerControlAccess();
310 sal_Int16 nSelect
= 0;
311 Sequence
<OUString
> aListBoxEntries
{
312 ScResId(STR_ANCHOR_TO_CELL
),
313 ScResId(STR_ANCHOR_TO_CELL_RESIZE
),
314 ScResId(STR_ANCHOR_TO_PAGE
)
318 Any
aTemplates(&aListBoxEntries
, cppu::UnoType
<decltype(aListBoxEntries
)>::get());
320 xCtrlAcc
->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
,
321 ui::dialogs::ListboxControlActions::ADD_ITEMS
, aTemplates
);
323 Any
aSelectPos(&nSelect
, cppu::UnoType
<decltype(nSelect
)>::get());
324 xCtrlAcc
->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
,
325 ui::dialogs::ListboxControlActions::SET_SELECT_ITEM
, aSelectPos
);
327 catch (const Exception
&)
329 SAL_WARN("sc", "control access failed");
332 if( aDlg
.Execute() == ERRCODE_NONE
)
335 ErrCode nError
= aDlg
.GetGraphic(aGraphic
);
336 if( nError
== ERRCODE_NONE
)
338 OUString aFileName
= aDlg
.GetPath();
339 const OUString
& aFilterName
= aDlg
.GetDetectedFilter();
340 bool bAsLink
= aDlg
.IsAsLink();
342 // really store as link only?
343 if( bAsLink
&& officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() )
345 SvxLinkWarningDialog
aWarnDlg(pWin
? pWin
->GetFrameWeld() : nullptr, aFileName
);
346 if (aWarnDlg
.run() != RET_OK
)
347 bAsLink
= false; // don't store as link
350 // Anchor to cell or to page?
351 Any aAnchorValue
= xCtrlAcc
->getValue(
352 ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
,
353 ui::dialogs::ListboxControlActions::GET_SELECTED_ITEM
);
355 aAnchorValue
>>= sAnchor
;
357 ScAnchorType aAnchorType
;
358 if (sAnchor
== ScResId(STR_ANCHOR_TO_CELL
))
359 aAnchorType
= SCA_CELL
;
360 else if (sAnchor
== ScResId(STR_ANCHOR_TO_CELL_RESIZE
))
361 aAnchorType
= SCA_CELL_RESIZE
;
362 else if (sAnchor
== ScResId(STR_ANCHOR_TO_PAGE
))
363 aAnchorType
= SCA_PAGE
;
365 aAnchorType
= SCA_DONTKNOW
;
367 lcl_InsertGraphic( aGraphic
, aFileName
, bAsLink
, false, rViewSh
, pWindow
, pView
, aAnchorType
);
369 // append items for recording
370 rReq
.AppendItem( SfxStringItem( SID_INSERT_GRAPHIC
, aFileName
) );
371 rReq
.AppendItem( SfxStringItem( FN_PARAM_FILTER
, aFilterName
) );
372 rReq
.AppendItem( SfxBoolItem( FN_PARAM_1
, bAsLink
) );
377 // error is handled in SvxOpenGraphicDialog::GetGraphic
383 FuInsertGraphic::~FuInsertGraphic()
387 FuInsertMedia::FuInsertMedia( ScTabViewShell
& rViewSh
,
391 const SfxRequest
& rReq
) :
392 FuPoor(rViewSh
, pWin
, pViewP
, pDoc
, rReq
)
394 #if HAVE_FEATURE_AVMEDIA
396 const SfxItemSet
* pReqArgs
= rReq
.GetArgs();
399 const SvxSizeItem
* pSizeItem
= rReq
.GetArg
<SvxSizeItem
>(FN_PARAM_1
);
400 const SfxBoolItem
* pLinkItem
= rReq
.GetArg
<SfxBoolItem
>(FN_PARAM_2
);
401 const bool bSizeUnknown
= !pSizeItem
;
406 const SfxStringItem
* pStringItem
= dynamic_cast<const SfxStringItem
*>( &pReqArgs
->Get( rReq
.GetSlot() ) );
410 aURL
= pStringItem
->GetValue();
411 bAPI
= aURL
.getLength();
415 bool bLink(pLinkItem
? pLinkItem
->GetValue() : true);
416 bool bInsertMedia
= bAPI
;
418 bInsertMedia
= ::avmedia::MediaWindow::executeMediaURLDialog(pWin
? pWin
->GetFrameWeld() : nullptr, aURL
, &bLink
);
424 aPrefSize
= pSizeItem
->GetSize();
431 css::uno::Reference
<css::frame::XDispatchProvider
> xDispatchProvider(rViewShell
.GetViewFrame().GetFrame().GetFrameInterface(), css::uno::UNO_QUERY
);
433 rtl::Reference
<avmedia::PlayerListener
> xPlayerListener(new avmedia::PlayerListener(
434 [xDispatchProvider
, aURL
, bLink
](const css::uno::Reference
<css::media::XPlayer
>& rPlayer
){
435 css::awt::Size aSize
= rPlayer
->getPreferredPlayerWindowSize();
436 avmedia::MediaWindow::dispatchInsertAVMedia(xDispatchProvider
, aSize
, aURL
, bLink
);
439 const bool bIsMediaURL
= ::avmedia::MediaWindow::isMediaURL(aURL
, u
""_ustr
/*TODO?*/, true, xPlayerListener
);
444 if (!bIsMediaURL
&& !bAPI
)
445 ::avmedia::MediaWindow::executeFormatErrorBox(pWindow
? pWindow
->GetFrameWeld() : nullptr);
453 lcl_InsertMedia(aURL
, bAPI
, &rViewSh
, pWindow
, pView
, aPrefSize
, bLink
);
460 FuInsertMedia::~FuInsertMedia()
464 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */