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 <sal/log.hxx>
23 #include <sfx2/opengrf.hxx>
24 #include <svx/svdograf.hxx>
25 #include <svx/svdomedia.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svdpagv.hxx>
28 #include <svx/svdview.hxx>
29 #include <svx/linkwarn.hxx>
30 #include <svx/svxids.hrc>
31 #include <vcl/graphicfilter.hxx>
32 #include <svl/stritem.hxx>
33 #include <svtools/miscopt.hxx>
34 #include <avmedia/mediawindow.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/weld.hxx>
37 #include <vcl/GraphicNativeTransform.hxx>
38 #include <vcl/GraphicNativeMetadata.hxx>
39 #include <fuinsert.hxx>
40 #include <tabvwsh.hxx>
41 #include <drwlayer.hxx>
42 #include <drawview.hxx>
43 #include <document.hxx>
44 #include <scresid.hxx>
45 #include <strings.hrc>
46 #include <globstr.hrc>
48 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
49 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
50 #include <com/sun/star/ui/dialogs/ListboxControlActions.hpp>
51 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
52 #include <com/sun/star/uno/Sequence.hxx>
55 using namespace css::uno
;
57 void ScLimitSizeOnDrawPage( Size
& rSize
, Point
& rPos
, const Size
& rPage
)
59 if ( !rPage
.Width() || !rPage
.Height() )
62 Size aPageSize
= rPage
;
63 bool bNegative
= aPageSize
.Width() < 0;
66 // make everything positive temporarily
67 aPageSize
.setWidth( -aPageSize
.Width() );
68 rPos
.setX( -rPos
.X() - rSize
.Width() );
71 if ( rSize
.Width() > aPageSize
.Width() || rSize
.Height() > aPageSize
.Height() )
73 double fX
= aPageSize
.Width() / static_cast<double>(rSize
.Width());
74 double fY
= aPageSize
.Height() / static_cast<double>(rSize
.Height());
78 rSize
.setWidth( aPageSize
.Width() );
79 rSize
.setHeight( static_cast<long>( rSize
.Height() * fX
) );
83 rSize
.setHeight( aPageSize
.Height() );
84 rSize
.setWidth( static_cast<long>( rSize
.Width() * fY
) );
93 if ( rPos
.X() + rSize
.Width() > aPageSize
.Width() )
94 rPos
.setX( aPageSize
.Width() - rSize
.Width() );
95 if ( rPos
.Y() + rSize
.Height() > aPageSize
.Height() )
96 rPos
.setY( aPageSize
.Height() - rSize
.Height() );
99 rPos
.setX( -rPos
.X() - rSize
.Width() ); // back to real position
102 static void lcl_InsertGraphic( const Graphic
& rGraphic
,
103 const OUString
& rFileName
, const OUString
& rFilterName
, bool bAsLink
, bool bApi
,
104 ScTabViewShell
& rViewSh
, const vcl::Window
* pWindow
, SdrView
* pView
,
105 ScAnchorType aAnchorType
= SCA_CELL
)
107 Graphic
& rGraphic1
= const_cast<Graphic
&>(rGraphic
);
108 GraphicNativeMetadata aMetadata
;
109 if ( aMetadata
.read(rGraphic1
) )
111 const sal_uInt16 aRotation
= aMetadata
.getRotation();
114 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(nullptr, VclMessageType::Question
,VclButtonsType::YesNo
,ScResId(STR_QUERYROTATION
)));
115 if (xQueryBox
->run() == RET_YES
)
117 GraphicNativeTransform
aTransform( rGraphic1
);
118 aTransform
.rotate( aRotation
);
122 ScDrawView
* pDrawView
= rViewSh
.GetScDrawView();
124 // #i123922# check if an existing object is selected; if yes, evtl. replace
125 // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
126 // style for other objects
127 if(pDrawView
&& 1 == pDrawView
->GetMarkedObjectCount())
129 SdrObject
* pPickObj
= pDrawView
->GetMarkedObjectByIndex(0);
133 //sal_Int8 nAction(DND_ACTION_MOVE);
135 const OUString
aBeginUndo(ScResId(STR_UNDO_DRAGDROP
));
137 SdrObject
* pResult
= pDrawView
->ApplyGraphicToObject(
141 bAsLink
? rFileName
: OUString(),
142 bAsLink
? rFilterName
: OUString());
146 // we are done; mark the modified/new object
147 pDrawView
->MarkObj(pResult
, pDrawView
->GetSdrPageView());
153 // set the size so the graphic has its original pixel size
154 // at 100% view scale (as in SetMarkedOriginalSize),
155 // instead of respecting the current view scale
156 MapMode aSourceMap
= rGraphic
.GetPrefMapMode();
157 MapMode
aDestMap( MapUnit::Map100thMM
);
158 if ( aSourceMap
.GetMapUnit() == MapUnit::MapPixel
&& pDrawView
)
160 Fraction aScaleX
, aScaleY
;
161 pDrawView
->CalcNormScale( aScaleX
, aScaleY
);
162 aDestMap
.SetScaleX(aScaleX
);
163 aDestMap
.SetScaleY(aScaleY
);
165 Size aLogicSize
= pWindow
->LogicToLogic(
166 rGraphic
.GetPrefSize(), &aSourceMap
, &aDestMap
);
170 SdrPageView
* pPV
= pView
->GetSdrPageView();
171 SdrPage
* pPage
= pPV
->GetPage();
172 Point aInsertPos
= rViewSh
.GetInsertPos();
174 ScViewData
& rData
= rViewSh
.GetViewData();
175 if ( rData
.GetDocument()->IsNegativePage( rData
.GetTabNo() ) )
176 aInsertPos
.AdjustX( -(aLogicSize
.Width()) ); // move position to left edge
178 ScLimitSizeOnDrawPage( aLogicSize
, aInsertPos
, pPage
->GetSize() );
180 tools::Rectangle
aRect ( aInsertPos
, aLogicSize
);
182 SdrGrafObj
* pObj
= new SdrGrafObj(
183 pView
->getSdrModelFromSdrView(), // TTTT pView should be reference
187 // calling SetGraphicLink here doesn't work
188 // Yes, due to the SdrObject had no SdrModel
189 // Path is no longer used as name for the graphics object
191 ScDrawLayer
* pLayer
= static_cast<ScDrawLayer
*>(pView
->GetModel());
192 OUString aName
= pLayer
->GetNewGraphicName(); // "Graphics"
193 pObj
->SetName(aName
);
195 if (aAnchorType
== SCA_CELL
|| aAnchorType
== SCA_CELL_RESIZE
)
196 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *(rData
.GetDocument()), rData
.GetTabNo(),
197 aAnchorType
== SCA_CELL_RESIZE
);
199 // don't select if from (dispatch) API, to allow subsequent cell operations
200 SdrInsertFlags nInsOptions
= bApi
? SdrInsertFlags::DONTMARK
: SdrInsertFlags::NONE
;
201 bool bSuccess
= pView
->InsertObjectAtView( pObj
, *pPV
, nInsOptions
);
203 // SetGraphicLink has to be used after inserting the object,
204 // otherwise an empty graphic is swapped in and the contact stuff crashes.
206 if (bSuccess
&& bAsLink
)
207 pObj
->SetGraphicLink( rFileName
, ""/*TODO?*/, rFilterName
);
210 static void lcl_InsertMedia( const OUString
& rMediaURL
, bool bApi
,
211 ScTabViewShell
* pViewSh
, const vcl::Window
* pWindow
, SdrView
* pView
,
212 const Size
& rPrefSize
, bool const bLink
)
214 SdrPageView
* pPV
= pView
->GetSdrPageView();
215 SdrPage
* pPage
= pPV
->GetPage();
216 ScViewData
& rData
= pViewSh
->GetViewData();
217 Point
aInsertPos( pViewSh
->GetInsertPos() );
220 if( rPrefSize
.Width() && rPrefSize
.Height() )
223 aSize
= pWindow
->PixelToLogic(rPrefSize
, MapMode(MapUnit::Map100thMM
));
225 aSize
= Application::GetDefaultDevice()->PixelToLogic(rPrefSize
, MapMode(MapUnit::Map100thMM
));
228 aSize
= Size( 5000, 5000 );
230 ScLimitSizeOnDrawPage( aSize
, aInsertPos
, pPage
->GetSize() );
232 if( rData
.GetDocument()->IsNegativePage( rData
.GetTabNo() ) )
233 aInsertPos
.AdjustX( -(aSize
.Width()) );
242 uno::Reference
<frame::XModel
> const xModel(
243 rData
.GetDocument()->GetDocumentShell()->GetModel());
244 #if HAVE_FEATURE_AVMEDIA
245 bool const bRet
= ::avmedia::EmbedMedia(xModel
, rMediaURL
, realURL
);
246 if (!bRet
) { return; }
252 SdrMediaObj
* pObj
= new SdrMediaObj(
253 *rData
.GetDocument()->GetDrawLayer(),
254 tools::Rectangle(aInsertPos
, aSize
));
256 pObj
->setURL( realURL
, ""/*TODO?*/ );
257 pView
->InsertObjectAtView( pObj
, *pPV
, bApi
? SdrInsertFlags::DONTMARK
: SdrInsertFlags::NONE
);
260 FuInsertGraphic::FuInsertGraphic( ScTabViewShell
& rViewSh
,
265 : FuPoor(rViewSh
, pWin
, pViewP
, pDoc
, rReq
)
267 const SfxItemSet
* pReqArgs
= rReq
.GetArgs();
268 const SfxPoolItem
* pItem
;
270 pReqArgs
->GetItemState( SID_INSERT_GRAPHIC
, true, &pItem
) == SfxItemState::SET
)
272 OUString aFileName
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
274 OUString aFilterName
;
275 if ( pReqArgs
->GetItemState( FN_PARAM_FILTER
, true, &pItem
) == SfxItemState::SET
)
276 aFilterName
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
278 bool bAsLink
= false;
279 if ( pReqArgs
->GetItemState( FN_PARAM_1
, true, &pItem
) == SfxItemState::SET
)
280 bAsLink
= static_cast<const SfxBoolItem
*>(pItem
)->GetValue();
283 ErrCode nError
= GraphicFilter::LoadGraphic( aFileName
, aFilterName
, aGraphic
, &GraphicFilter::GetGraphicFilter() );
284 if ( nError
== ERRCODE_NONE
)
286 lcl_InsertGraphic( aGraphic
, aFileName
, aFilterName
, bAsLink
, true, rViewSh
, pWindow
, pView
);
291 SvxOpenGraphicDialog
aDlg(ScResId(STR_INSERTGRAPHIC
), pWin
? pWin
->GetFrameWeld() : nullptr,
292 ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
);
294 Reference
<ui::dialogs::XFilePickerControlAccess
> xCtrlAcc
= aDlg
.GetFilePickerControlAccess();
295 sal_Int16 nSelect
= 0;
296 Sequence
<OUString
> aListBoxEntries
{
297 ScResId(STR_ANCHOR_TO_CELL
),
298 ScResId(STR_ANCHOR_TO_CELL_RESIZE
),
299 ScResId(STR_ANCHOR_TO_PAGE
)
303 Any
aTemplates(&aListBoxEntries
, cppu::UnoType
<decltype(aListBoxEntries
)>::get());
305 xCtrlAcc
->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
,
306 ui::dialogs::ListboxControlActions::ADD_ITEMS
, aTemplates
);
308 Any
aSelectPos(&nSelect
, cppu::UnoType
<decltype(nSelect
)>::get());
309 xCtrlAcc
->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
,
310 ui::dialogs::ListboxControlActions::SET_SELECT_ITEM
, aSelectPos
);
312 catch (const Exception
&)
314 SAL_WARN("sc", "control access failed");
317 if( aDlg
.Execute() == ERRCODE_NONE
)
320 ErrCode nError
= aDlg
.GetGraphic(aGraphic
);
321 if( nError
== ERRCODE_NONE
)
323 OUString aFileName
= aDlg
.GetPath();
324 const OUString
& aFilterName
= aDlg
.GetDetectedFilter();
325 bool bAsLink
= aDlg
.IsAsLink();
327 // really store as link only?
328 if( bAsLink
&& SvtMiscOptions().ShowLinkWarningDialog() )
330 SvxLinkWarningDialog
aWarnDlg(pWin
? pWin
->GetFrameWeld() : nullptr, aFileName
);
331 if (aWarnDlg
.run() != RET_OK
)
332 bAsLink
= false; // don't store as link
335 // Anchor to cell or to page?
336 Any aAnchorValue
= xCtrlAcc
->getValue(
337 ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
,
338 ui::dialogs::ListboxControlActions::GET_SELECTED_ITEM
);
340 aAnchorValue
>>= sAnchor
;
342 ScAnchorType aAnchorType
;
343 if (sAnchor
== ScResId(STR_ANCHOR_TO_CELL
))
344 aAnchorType
= SCA_CELL
;
345 else if (sAnchor
== ScResId(STR_ANCHOR_TO_CELL_RESIZE
))
346 aAnchorType
= SCA_CELL_RESIZE
;
347 else if (sAnchor
== ScResId(STR_ANCHOR_TO_PAGE
))
348 aAnchorType
= SCA_PAGE
;
350 aAnchorType
= SCA_DONTKNOW
;
352 lcl_InsertGraphic( aGraphic
, aFileName
, aFilterName
, bAsLink
, false, rViewSh
, pWindow
, pView
, aAnchorType
);
354 // append items for recording
355 rReq
.AppendItem( SfxStringItem( SID_INSERT_GRAPHIC
, aFileName
) );
356 rReq
.AppendItem( SfxStringItem( FN_PARAM_FILTER
, aFilterName
) );
357 rReq
.AppendItem( SfxBoolItem( FN_PARAM_1
, bAsLink
) );
362 // error is handled in SvxOpenGraphicDialog::GetGraphic
368 FuInsertGraphic::~FuInsertGraphic()
372 FuInsertMedia::FuInsertMedia( ScTabViewShell
& rViewSh
,
376 const SfxRequest
& rReq
) :
377 FuPoor(rViewSh
, pWin
, pViewP
, pDoc
, rReq
)
380 const SfxItemSet
* pReqArgs
= rReq
.GetArgs();
385 const SfxStringItem
* pStringItem
= dynamic_cast<const SfxStringItem
*>( &pReqArgs
->Get( rReq
.GetSlot() ) );
389 aURL
= pStringItem
->GetValue();
390 bAPI
= aURL
.getLength();
396 #if HAVE_FEATURE_AVMEDIA
397 || ::avmedia::MediaWindow::executeMediaURLDialog(pWin
? pWin
->GetFrameWeld() : nullptr, aURL
, &bLink
)
406 #if HAVE_FEATURE_AVMEDIA
407 if( !::avmedia::MediaWindow::isMediaURL( aURL
, ""/*TODO?*/, true, &aPrefSize
) )
413 ::avmedia::MediaWindow::executeFormatErrorBox(pWindow
? pWindow
->GetFrameWeld() : nullptr);
418 lcl_InsertMedia( aURL
, bAPI
, &rViewSh
, pWindow
, pView
, aPrefSize
,
427 FuInsertMedia::~FuInsertMedia()
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */