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 <com/sun/star/drawing/GraphicExportFilter.hpp>
21 
22 #include <vcl/errinf.hxx>
23 #include <vcl/weld.hxx>
24 #include <sfx2/sfxsids.hrc>
25 #include <sfx2/docfile.hxx>
26 #include <sfx2/docfilt.hxx>
27 #include <sfx2/sfxuno.hxx>
28 #include <svx/svdograf.hxx>
29 
30 #include <strings.hrc>
31 #include <DrawViewShell.hxx>
32 #include <DrawDocShell.hxx>
33 
34 #include <comphelper/processfactory.hxx>
35 #include <vcl/graphicfilter.hxx>
36 #include <vcl/svapp.hxx>
37 
38 #include <sdpage.hxx>
39 #include <drawdoc.hxx>
40 #include <sdresid.hxx>
41 #include <sdgrffilter.hxx>
42 #include <ViewShellBase.hxx>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/beans/PropertyValues.hpp>
45 #include <com/sun/star/lang/XComponent.hpp>
46 #include <com/sun/star/view/XSelectionSupplier.hpp>
47 #include <cppuhelper/implbase.hxx>
48 #include <com/sun/star/task/XInteractionHandler.hpp>
49 #include <com/sun/star/task/XInteractionRequest.hpp>
50 #include <com/sun/star/drawing/GraphicFilterRequest.hpp>
51 
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::lang;
55 using namespace ::com::sun::star::beans;
56 using namespace ::com::sun::star::graphic;
57 using namespace ::com::sun::star::io;
58 using namespace ::com::sun::star::ucb;
59 using namespace com::sun::star::ui::dialogs;
60 using namespace ::sfx2;
61 
62 class SdGRFFilter_ImplInteractionHdl : public ::cppu::WeakImplHelper< css::task::XInteractionHandler >
63 {
64     css::uno::Reference< css::task::XInteractionHandler > m_xInter;
65     ErrCode nFilterError;
66 
67     public:
68 
SdGRFFilter_ImplInteractionHdl(css::uno::Reference<css::task::XInteractionHandler> const & xInteraction)69     explicit SdGRFFilter_ImplInteractionHdl( css::uno::Reference< css::task::XInteractionHandler > const & xInteraction ) :
70         m_xInter( xInteraction ),
71         nFilterError( ERRCODE_NONE )
72         {}
73 
GetErrorCode() const74     ErrCode const & GetErrorCode() const { return nFilterError; };
75 
76     virtual void SAL_CALL   handle( const css::uno::Reference< css::task::XInteractionRequest >& ) override;
77 };
78 
handle(const css::uno::Reference<css::task::XInteractionRequest> & xRequest)79 void SdGRFFilter_ImplInteractionHdl::handle( const css::uno::Reference< css::task::XInteractionRequest >& xRequest )
80 {
81     if( !m_xInter.is() )
82         return;
83 
84     css::drawing::GraphicFilterRequest aErr;
85     if ( xRequest->getRequest() >>= aErr )
86         nFilterError = ErrCode(aErr.ErrCode);
87     else
88         m_xInter->handle( xRequest );
89 }
90 
91 
SdGRFFilter(SfxMedium & rMedium,::sd::DrawDocShell & rDocShell)92 SdGRFFilter::SdGRFFilter( SfxMedium& rMedium, ::sd::DrawDocShell& rDocShell ) :
93     SdFilter( rMedium, rDocShell )
94 {
95 }
96 
~SdGRFFilter()97 SdGRFFilter::~SdGRFFilter()
98 {
99 }
100 
HandleGraphicFilterError(ErrCode nFilterError,ErrCode nStreamError)101 void SdGRFFilter::HandleGraphicFilterError( ErrCode nFilterError, ErrCode nStreamError )
102 {
103     if (ERRCODE_NONE != nStreamError)
104     {
105         ErrorHandler::HandleError(nStreamError);
106         return;
107     }
108 
109     const char* pId;
110 
111     if( nFilterError == ERRCODE_GRFILTER_OPENERROR )
112         pId = STR_IMPORT_GRFILTER_OPENERROR;
113     else if( nFilterError == ERRCODE_GRFILTER_IOERROR )
114         pId = STR_IMPORT_GRFILTER_IOERROR;
115     else if( nFilterError == ERRCODE_GRFILTER_FORMATERROR )
116         pId = STR_IMPORT_GRFILTER_FORMATERROR;
117     else if( nFilterError == ERRCODE_GRFILTER_VERSIONERROR )
118         pId = STR_IMPORT_GRFILTER_VERSIONERROR;
119     else if( nFilterError == ERRCODE_GRFILTER_TOOBIG )
120         pId = STR_IMPORT_GRFILTER_TOOBIG;
121     else if( nFilterError == ERRCODE_NONE )
122         pId = nullptr;
123     else
124         pId = STR_IMPORT_GRFILTER_FILTERERROR;
125 
126     if (pId && strcmp(pId, STR_IMPORT_GRFILTER_IOERROR) == 0)
127         ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
128     else
129     {
130         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(nullptr,
131                                                        VclMessageType::Warning, VclButtonsType::Ok, pId ? SdResId(pId) : OUString()));
132         xErrorBox->run();
133     }
134 }
135 
Import()136 bool SdGRFFilter::Import()
137 {
138     Graphic         aGraphic;
139     const OUString  aFileName( mrMedium.GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
140     GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
141     const sal_uInt16 nFilter = rGraphicFilter.GetImportFormatNumberForTypeName( mrMedium.GetFilter()->GetTypeName() );
142     bool        bRet = false;
143 
144     SvStream*       pIStm = mrMedium.GetInStream();
145     ErrCode         nReturn = pIStm ? rGraphicFilter.ImportGraphic( aGraphic, aFileName, *pIStm, nFilter ) : ErrCode(1);
146 
147     if( nReturn )
148         HandleGraphicFilterError( nReturn, rGraphicFilter.GetLastError().nStreamError );
149     else
150     {
151         if( mrDocument.GetPageCount() == 0 )
152             mrDocument.CreateFirstPages();
153 
154         SdPage*     pPage = mrDocument.GetSdPage( 0, PageKind::Standard );
155         Point       aPos;
156         Size        aPagSize( pPage->GetSize() );
157         Size        aGrfSize( OutputDevice::LogicToLogic( aGraphic.GetPrefSize(),
158                                 aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)));
159 
160         aPagSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) );
161         aPagSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) );
162 
163         // scale to fit page
164         if ( ( ( aGrfSize.Height() > aPagSize.Height() ) || ( aGrfSize.Width() > aPagSize.Width() ) ) &&
165                 aGrfSize.Height() && aPagSize.Height() )
166         {
167             double fGrfWH = static_cast<double>(aGrfSize.Width()) / aGrfSize.Height();
168             double fWinWH = static_cast<double>(aPagSize.Width()) / aPagSize.Height();
169 
170             // adjust graphic to page size (scales)
171             if( fGrfWH < fWinWH )
172             {
173                 aGrfSize.setWidth( static_cast<long>( aPagSize.Height() * fGrfWH ) );
174                 aGrfSize.setHeight( aPagSize.Height() );
175             }
176             else if( fGrfWH > 0.F )
177             {
178                 aGrfSize.setWidth( aPagSize.Width() );
179                 aGrfSize.setHeight( static_cast<long>( aPagSize.Width() / fGrfWH ) );
180             }
181         }
182 
183         // set output rectangle for graphic
184         aPos.setX( ( ( aPagSize.Width() - aGrfSize.Width() ) >> 1 ) + pPage->GetLeftBorder() );
185         aPos.setY( ( ( aPagSize.Height() - aGrfSize.Height() ) >> 1 )  + pPage->GetUpperBorder() );
186 
187         pPage->InsertObject(
188             new SdrGrafObj(
189                 pPage->getSdrModelFromSdrPage(),
190                 aGraphic,
191                 ::tools::Rectangle(aPos, aGrfSize)));
192         bRet = true;
193     }
194 
195     return bRet;
196 }
197 
Export()198 bool SdGRFFilter::Export()
199 {
200     // SJ: todo: error handling, the GraphicExportFilter does not support proper errorhandling
201     bool bRet = false;
202 
203     uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
204     uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( xContext );
205 
206     SdPage* pPage = nullptr;
207     sd::DrawViewShell*  pDrawViewShell = dynamic_cast<::sd::DrawViewShell* >(mrDocShell.GetViewShell() );
208 
209     PageKind ePageKind = PageKind::Standard;
210     if( pDrawViewShell )
211     {
212         ePageKind = pDrawViewShell->GetPageKind();
213         if( PageKind::Handout == ePageKind )
214             pPage = mrDocument.GetSdPage( 0, PageKind::Handout );
215         else
216             pPage = pDrawViewShell->GetActualPage();
217     }
218     else
219         pPage = mrDocument.GetSdPage( 0, PageKind::Standard );
220 
221     if ( pPage )
222     {
223         // taking the 'correct' page number, seems that there might exist a better method to archive this
224         pPage = mrDocument.GetSdPage( pPage->GetPageNum() ? ( pPage->GetPageNum() - 1 ) >> 1 : 0, ePageKind );
225         if ( pPage )
226         {
227             uno::Reference< lang::XComponent > xSource( pPage->getUnoPage(), uno::UNO_QUERY );
228             SfxItemSet* pSet = mrMedium.GetItemSet();
229             if ( pSet && xSource.is() )
230             {
231                 const OUString aTypeName( mrMedium.GetFilter()->GetTypeName() );
232                 GraphicFilter &rGraphicFilter = GraphicFilter::GetGraphicFilter();
233                 const sal_uInt16 nFilter = rGraphicFilter.GetExportFormatNumberForTypeName( aTypeName );
234                 if ( nFilter != GRFILTER_FORMAT_NOTFOUND )
235                 {
236                     uno::Reference< task::XInteractionHandler > xInteractionHandler;
237 
238                     beans::PropertyValues aArgs;
239                     TransformItems( SID_SAVEASDOC, *pSet, aArgs );
240 
241                     const OUString sFilterName( "FilterName" );
242                     OUString sShortName( rGraphicFilter.GetExportFormatShortName( nFilter ) );
243 
244                     bool    bFilterNameFound = false;
245                     for ( auto& rArg : aArgs )
246                     {
247                         OUString& rStr = rArg.Name;
248                         if ( rStr == sFilterName )
249                         {
250                             bFilterNameFound = true;
251                             rArg.Value <<= sShortName;
252                         }
253                         else if ( rStr == "InteractionHandler" )
254                         {
255                             uno::Reference< task::XInteractionHandler > xHdl;
256                             if ( rArg.Value >>= xHdl )
257                             {
258                                 xInteractionHandler = new SdGRFFilter_ImplInteractionHdl( xHdl );
259                                 rArg.Value <<= xInteractionHandler;
260                             }
261                         }
262                     }
263                     if ( !bFilterNameFound )
264                     {
265                         sal_Int32 nCount = aArgs.getLength();
266                         aArgs.realloc( nCount + 1 );
267                         aArgs[ nCount ].Name = sFilterName;
268                         aArgs[ nCount ].Value <<= sShortName;
269                     }
270 
271                     // take selection if needed
272                     if( ( SfxItemState::SET == pSet->GetItemState( SID_SELECTION ) )
273                         && pSet->Get( SID_SELECTION ).GetValue()
274                         && pDrawViewShell )
275                     {
276                         uno::Reference< view::XSelectionSupplier > xSelectionSupplier(
277                             pDrawViewShell->GetViewShellBase().GetController(), uno::UNO_QUERY );
278                         if ( xSelectionSupplier.is() )
279                         {
280                             uno::Any aSelection( xSelectionSupplier->getSelection() );
281                             uno::Reference< lang::XComponent > xSelection;
282                             if ( aSelection >>= xSelection )
283                                 xSource = xSelection;
284                         }
285                     }
286                     xExporter->setSourceDocument( xSource );
287                     bRet = xExporter->filter( aArgs );
288                     if ( !bRet && xInteractionHandler.is() )
289                         SdGRFFilter::HandleGraphicFilterError(
290                             static_cast< SdGRFFilter_ImplInteractionHdl* >( xInteractionHandler.get() )->GetErrorCode(),
291                                             rGraphicFilter.GetLastError().nStreamError );
292                 }
293              }
294         }
295     }
296     return bRet;
297 }
298 
299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
300