1
0
Fork 0
libreoffice/sc/source/ui/drawfunc/fuins1.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

464 lines
17 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <config_features.h>
#include <officecfg/Office/Common.hxx>
#include <editeng/sizeitem.hxx>
#include <sal/log.hxx>
#include <sfx2/lokhelper.hxx>
#include <sfx2/opengrf.hxx>
#include <sfx2/viewfrm.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdomedia.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdview.hxx>
#include <svx/linkwarn.hxx>
#include <svx/svxids.hrc>
#include <vcl/graphicfilter.hxx>
#include <svl/stritem.hxx>
#include <avmedia/mediawindow.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <vcl/GraphicNativeTransform.hxx>
#include <vcl/GraphicNativeMetadata.hxx>
#include <fuinsert.hxx>
#include <tabvwsh.hxx>
#include <drwlayer.hxx>
#include <drawview.hxx>
#include <document.hxx>
#include <scresid.hxx>
#include <strings.hrc>
#include <globstr.hrc>
#include <comphelper/lok.hxx>
#include <tools/hostfilter.hxx>
#include <tools/urlobj.hxx>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/media/XPlayer.hpp>
#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#include <com/sun/star/ui/dialogs/ListboxControlActions.hpp>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/uno/Sequence.hxx>
using namespace css;
using namespace css::uno;
void ScLimitSizeOnDrawPage( Size& rSize, Point& rPos, const Size& rPage )
{
if ( !rPage.Width() || !rPage.Height() )
return;
Size aPageSize = rPage;
bool bNegative = aPageSize.Width() < 0;
if ( bNegative )
{
// make everything positive temporarily
aPageSize.setWidth( -aPageSize.Width() );
rPos.setX( -rPos.X() - rSize.Width() );
}
if ( rSize.Width() > aPageSize.Width() || rSize.Height() > aPageSize.Height() )
{
double fX = aPageSize.Width() / static_cast<double>(rSize.Width());
double fY = aPageSize.Height() / static_cast<double>(rSize.Height());
if ( fX < fY )
{
rSize.setWidth( aPageSize.Width() );
rSize.setHeight( static_cast<tools::Long>( rSize.Height() * fX ) );
}
else
{
rSize.setHeight( aPageSize.Height() );
rSize.setWidth( static_cast<tools::Long>( rSize.Width() * fY ) );
}
if (!rSize.Width())
rSize.setWidth( 1 );
if (!rSize.Height())
rSize.setHeight( 1 );
}
if ( rPos.X() + rSize.Width() > aPageSize.Width() )
rPos.setX( aPageSize.Width() - rSize.Width() );
if ( rPos.Y() + rSize.Height() > aPageSize.Height() )
rPos.setY( aPageSize.Height() - rSize.Height() );
if ( bNegative )
rPos.setX( -rPos.X() - rSize.Width() ); // back to real position
}
static void lcl_InsertGraphic( const Graphic& rGraphic,
const OUString& rFileName, bool bAsLink, bool bApi,
ScTabViewShell& rViewSh, const vcl::Window* pWindow, SdrView* pView,
ScAnchorType aAnchorType = SCA_CELL )
{
Graphic& rGraphic1 = const_cast<Graphic &>(rGraphic);
GraphicNativeMetadata aMetadata;
if ( aMetadata.read(rGraphic1) )
{
const Degree10 aRotation = aMetadata.getRotation();
if (aRotation)
{
GraphicNativeTransform aTransform( rGraphic1 );
aTransform.rotate( aRotation );
}
}
ScDrawView* pDrawView = rViewSh.GetScDrawView();
// #i123922# check if an existing object is selected; if yes, evtl. replace
// the graphic for a SdrGraphObj (including link state updates) or adapt the fill
// style for other objects
if(pDrawView)
{
const SdrMarkList& rMarkList = pDrawView->GetMarkedObjectList();
if (1 == rMarkList.GetMarkCount())
{
SdrObject* pPickObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
if(pPickObj)
{
//sal_Int8 nAction(DND_ACTION_MOVE);
//Point aPos;
const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
SdrObject* pResult = pDrawView->ApplyGraphicToObject(
*pPickObj,
rGraphic1,
aBeginUndo,
bAsLink ? rFileName : OUString());
if(pResult)
{
// we are done; mark the modified/new object
pDrawView->MarkObj(pResult, pDrawView->GetSdrPageView());
return;
}
}
}
}
// set the size so the graphic has its original pixel size
// at 100% view scale (as in SetMarkedOriginalSize),
// instead of respecting the current view scale
MapMode aSourceMap = rGraphic.GetPrefMapMode();
MapMode aDestMap( MapUnit::Map100thMM );
if ( aSourceMap.GetMapUnit() == MapUnit::MapPixel && pDrawView )
{
Fraction aScaleX, aScaleY;
pDrawView->CalcNormScale( aScaleX, aScaleY );
aDestMap.SetScaleX(aScaleX);
aDestMap.SetScaleY(aScaleY);
}
Size aLogicSize = pWindow->LogicToLogic(
rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );
// Limit size
SdrPageView* pPV = pView->GetSdrPageView();
SdrPage* pPage = pPV->GetPage();
Point aInsertPos = rViewSh.GetInsertPos();
ScViewData& rData = rViewSh.GetViewData();
if ( rData.GetDocument().IsNegativePage( rData.GetTabNo() ) )
aInsertPos.AdjustX( -(aLogicSize.Width()) ); // move position to left edge
ScLimitSizeOnDrawPage( aLogicSize, aInsertPos, pPage->GetSize() );
tools::Rectangle aRect ( aInsertPos, aLogicSize );
rtl::Reference<SdrGrafObj> pObj = new SdrGrafObj(
pView->getSdrModelFromSdrView(), // TTTT pView should be reference
rGraphic1,
aRect);
// calling SetGraphicLink here doesn't work
// Yes, due to the SdrObject had no SdrModel
// Path is no longer used as name for the graphics object
ScDrawLayer* pLayer = static_cast<ScDrawLayer*>(&pView->GetModel());
OUString aName = pLayer->GetNewGraphicName(); // "Graphics"
pObj->SetName(aName);
if (aAnchorType == SCA_CELL || aAnchorType == SCA_CELL_RESIZE)
ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rData.GetDocument(), rData.GetTabNo(),
aAnchorType == SCA_CELL_RESIZE);
// don't select if from (dispatch) API, to allow subsequent cell operations
SdrInsertFlags nInsOptions = (bApi && !comphelper::LibreOfficeKit::isActive()) ? SdrInsertFlags::DONTMARK : SdrInsertFlags::NONE;
bool bSuccess = pView->InsertObjectAtView( pObj.get(), *pPV, nInsOptions );
// SetGraphicLink has to be used after inserting the object,
// otherwise an empty graphic is swapped in and the contact stuff crashes.
// See #i37444#.
if (bSuccess && bAsLink)
pObj->SetGraphicLink( rFileName );
}
#if HAVE_FEATURE_AVMEDIA
static void lcl_InsertMedia( const OUString& rMediaURL, bool bApi,
ScTabViewShell* pViewSh, const vcl::Window* pWindow, SdrView* pView,
const Size& rPrefSize, bool const bLink )
{
SdrPageView* pPV = pView->GetSdrPageView();
SdrPage* pPage = pPV->GetPage();
ScViewData& rData = pViewSh->GetViewData();
Point aInsertPos( pViewSh->GetInsertPos() );
Size aSize;
if( rPrefSize.Width() && rPrefSize.Height() )
{
if( pWindow )
aSize = pWindow->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM));
else
aSize = Application::GetDefaultDevice()->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM));
}
else
aSize = Size( 5000, 5000 );
ScLimitSizeOnDrawPage( aSize, aInsertPos, pPage->GetSize() );
if( rData.GetDocument().IsNegativePage( rData.GetTabNo() ) )
aInsertPos.AdjustX( -(aSize.Width()) );
OUString realURL;
if (bLink)
{
realURL = rMediaURL;
}
else
{
uno::Reference<frame::XModel> const xModel(
rData.GetDocument().GetDocumentShell()->GetModel());
bool const bRet = ::avmedia::EmbedMedia(xModel, rMediaURL, realURL);
if (!bRet) { return; }
}
rtl::Reference<SdrMediaObj> pObj = new SdrMediaObj(
*rData.GetDocument().GetDrawLayer(),
tools::Rectangle(aInsertPos, aSize));
pObj->setURL( realURL, u""_ustr/*TODO?*/ );
pView->InsertObjectAtView( pObj.get(), *pPV, bApi ? SdrInsertFlags::DONTMARK : SdrInsertFlags::NONE );
}
#endif
FuInsertGraphic::FuInsertGraphic( ScTabViewShell& rViewSh,
vcl::Window* pWin,
ScDrawView* pViewP,
SdrModel* pDoc,
SfxRequest& rReq )
: FuPoor(rViewSh, pWin, pViewP, pDoc, rReq)
{
const SfxItemSet* pReqArgs = rReq.GetArgs();
const SfxStringItem* pGraphicItem;
if ( pReqArgs &&
(pGraphicItem = pReqArgs->GetItemIfSet( SID_INSERT_GRAPHIC, true )) )
{
const OUString& aFileName = pGraphicItem->GetValue();
OUString aFilterName;
if ( const SfxStringItem* pFilterItem = pReqArgs->GetItemIfSet( FN_PARAM_FILTER ) )
aFilterName = pFilterItem->GetValue();
bool bAsLink = false;
const SfxPoolItem* pItem;
if ( pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
bAsLink = static_cast<const SfxBoolItem*>(pItem)->GetValue();
if (comphelper::LibreOfficeKit::isActive())
{
INetURLObject aURL(aFileName);
if (INetProtocol::File != aURL.GetProtocol() && HostFilter::isForbidden(aURL.GetHost()))
SfxLokHelper::sendNetworkAccessError("insert");
}
Graphic aGraphic;
ErrCode nError = GraphicFilter::LoadGraphic( aFileName, aFilterName, aGraphic, &GraphicFilter::GetGraphicFilter() );
if ( nError == ERRCODE_NONE )
{
lcl_InsertGraphic( aGraphic, aFileName, bAsLink, true, rViewSh, pWindow, pView );
}
}
else
{
SvxOpenGraphicDialog aDlg(ScResId(STR_INSERTGRAPHIC), pWin ? pWin->GetFrameWeld() : nullptr,
ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR);
Reference<ui::dialogs::XFilePickerControlAccess> xCtrlAcc = aDlg.GetFilePickerControlAccess();
sal_Int16 nSelect = 0;
Sequence<OUString> aListBoxEntries {
ScResId(STR_ANCHOR_TO_CELL),
ScResId(STR_ANCHOR_TO_CELL_RESIZE),
ScResId(STR_ANCHOR_TO_PAGE)
};
try
{
Any aTemplates(&aListBoxEntries, cppu::UnoType<decltype(aListBoxEntries)>::get());
xCtrlAcc->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR,
ui::dialogs::ListboxControlActions::ADD_ITEMS, aTemplates);
Any aSelectPos(&nSelect, cppu::UnoType<decltype(nSelect)>::get());
xCtrlAcc->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR,
ui::dialogs::ListboxControlActions::SET_SELECT_ITEM, aSelectPos);
}
catch (const Exception&)
{
SAL_WARN("sc", "control access failed");
}
if( aDlg.Execute() == ERRCODE_NONE )
{
Graphic aGraphic;
ErrCode nError = aDlg.GetGraphic(aGraphic);
if( nError == ERRCODE_NONE )
{
OUString aFileName = aDlg.GetPath();
const OUString& aFilterName = aDlg.GetDetectedFilter();
bool bAsLink = aDlg.IsAsLink();
// really store as link only?
if( bAsLink && officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() )
{
SvxLinkWarningDialog aWarnDlg(pWin ? pWin->GetFrameWeld() : nullptr, aFileName);
if (aWarnDlg.run() != RET_OK)
bAsLink = false; // don't store as link
}
// Anchor to cell or to page?
Any aAnchorValue = xCtrlAcc->getValue(
ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR,
ui::dialogs::ListboxControlActions::GET_SELECTED_ITEM );
OUString sAnchor;
aAnchorValue >>= sAnchor;
ScAnchorType aAnchorType;
if (sAnchor == ScResId(STR_ANCHOR_TO_CELL))
aAnchorType = SCA_CELL;
else if (sAnchor == ScResId(STR_ANCHOR_TO_CELL_RESIZE))
aAnchorType = SCA_CELL_RESIZE;
else if (sAnchor == ScResId(STR_ANCHOR_TO_PAGE))
aAnchorType = SCA_PAGE;
else
aAnchorType = SCA_DONTKNOW;
lcl_InsertGraphic( aGraphic, aFileName, bAsLink, false, rViewSh, pWindow, pView, aAnchorType );
// append items for recording
rReq.AppendItem( SfxStringItem( SID_INSERT_GRAPHIC, aFileName ) );
rReq.AppendItem( SfxStringItem( FN_PARAM_FILTER, aFilterName ) );
rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bAsLink ) );
rReq.Done();
}
else
{
// error is handled in SvxOpenGraphicDialog::GetGraphic
}
}
}
}
FuInsertGraphic::~FuInsertGraphic()
{
}
FuInsertMedia::FuInsertMedia( ScTabViewShell& rViewSh,
vcl::Window* pWin,
ScDrawView* pViewP,
SdrModel* pDoc,
const SfxRequest& rReq ) :
FuPoor(rViewSh, pWin, pViewP, pDoc, rReq)
{
#if HAVE_FEATURE_AVMEDIA
OUString aURL;
const SfxItemSet* pReqArgs = rReq.GetArgs();
bool bAPI = false;
const SvxSizeItem* pSizeItem = rReq.GetArg<SvxSizeItem>(FN_PARAM_1);
const SfxBoolItem* pLinkItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2);
const bool bSizeUnknown = !pSizeItem;
Size aPrefSize;
if( pReqArgs )
{
const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( &pReqArgs->Get( rReq.GetSlot() ) );
if( pStringItem )
{
aURL = pStringItem->GetValue();
bAPI = aURL.getLength();
}
}
bool bLink(pLinkItem ? pLinkItem->GetValue() : true);
bool bInsertMedia = bAPI;
if (!bInsertMedia)
bInsertMedia = ::avmedia::MediaWindow::executeMediaURLDialog(pWin ? pWin->GetFrameWeld() : nullptr, aURL, &bLink);
if (!bInsertMedia)
return;
if (!bSizeUnknown)
{
aPrefSize = pSizeItem->GetSize();
}
else
{
if( pWin )
pWin->EnterWait();
css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(rViewShell.GetViewFrame().GetFrame().GetFrameInterface(), css::uno::UNO_QUERY);
rtl::Reference<avmedia::PlayerListener> xPlayerListener(new avmedia::PlayerListener(
[xDispatchProvider, aURL, bLink](const css::uno::Reference<css::media::XPlayer>& rPlayer){
css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize();
avmedia::MediaWindow::dispatchInsertAVMedia(xDispatchProvider, aSize, aURL, bLink);
}));
const bool bIsMediaURL = ::avmedia::MediaWindow::isMediaURL(aURL, u""_ustr/*TODO?*/, true, xPlayerListener);
if( pWin )
pWin->LeaveWait();
if (!bIsMediaURL && !bAPI)
::avmedia::MediaWindow::executeFormatErrorBox(pWindow ? pWindow->GetFrameWeld() : nullptr);
return;
}
if (pWin)
pWin->EnterWait();
lcl_InsertMedia(aURL, bAPI, &rViewSh, pWindow, pView, aPrefSize, bLink);
if (pWin)
pWin->LeaveWait();
#endif
}
FuInsertMedia::~FuInsertMedia()
{
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */